Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FDC3 For Web browsers #896

Open
robmoffat opened this issue Jan 19, 2023 · 59 comments · May be fixed by #1191
Open

FDC3 For Web browsers #896

robmoffat opened this issue Jan 19, 2023 · 59 comments · May be fixed by #1191
Labels
api FDC3 API Working Group enhancement New feature or request FDC3 for Web Browsers

Comments

@robmoffat
Copy link
Member

Enhancement Request

In a recent email on the FDC3 mailing list, @kriswest wrote:

... I also want to add that there is clearly significant interest in the community in enabling FDC3 use on the web. There is a strong use case in that it would enable better onboarding journeys with less drop-off (where you use an app on the web with others before adopting a desktop container or similar).

and:

But there are also additional challenges such as how to make the API available reliably without importing a proprietary module from a particular vendor into every app, how to deal with more than one implementation of API/Desktop Agent in the browser at once, how to do this reliably and securely within the browser sandbox etc.. Work needs to be done in the Standard to solve these issues and to make web browser use possible in a future FDC3 Standard version - which I believe is possible (and likely to involve using a vendor-agnostic FDC3 NPM module to detect and connect to API implementation(s)). However, we're going to need to do that work to enable the aforementioned API implementations to be compliant and if we fail to hold the line now on compliance with the current version of the FDC3 Standard, that may never happen.

Hence, I strongly encourage any vendors or firms working on API implementations that would fall outside current compliance requirements to work with the FDC3 maintainers and community, in general, to help move the Standard forward! The first step will be to raise an issue to bring to the Standards Working Group, which might then move to a Discussion Group to develop a proposal for additions to the Standard and its software. The maintainers meet again next week and will discuss getting such an issue on the books.

This is therefore a placeholder issue where we can begin to discuss how to solve this problem and potentially open up FDC3 to a wider audience.

@robmoffat robmoffat added the enhancement New feature or request label Jan 19, 2023
@robmoffat
Copy link
Member Author

robmoffat commented Jan 19, 2023

This is a problem with some prior art:

  • @ggeorgievx @ksgeorgieva @flashd2n from Tick42 have already implemented "Glue 42 Core" which provides a vendor-implementation of "FDC3 over the web"
  • @nkolba has been working on Connectifi, which is adjacent to this.
  • @nkolba has also been working on FDC3-Sail, which contains some of the parts to solve this problem (I think)
  • I have been thinking about for several months as part of project planning for FINOS for 2023 - I will share my thoughts in the comment below.

As @kriswest says in the quote above, he thinks there is interest within the community. I have personally talked to a number of App vendors who are confused as to why this isn't a thing already.

I am hoping we can have a discussion on this at the next maintainers' meeting and move this forwards

@robmoffat
Copy link
Member Author

robmoffat commented Jan 19, 2023

Here is my thinking so far on the subject (more to seed a debate rather than anything else).

  1. Glue Core uses PostMessage to allow FDC3 to communicate within-browser but across tabs. This is a promising line of inquiry and I'm hoping we can learn more from that team about how this works. There are security concerns here that I would like us to think through.

  2. In discussing this with @kriswest yesterday, we agreed that it would be nice to rally around a well-written Use Case. Perhaps this is where we should start?

  3. A further point we discussed is the need for what I am calling an FDC3 "wire protocol":

  • FDC3 Sail implements a bus for FDC3 messages between apps, with the agent acting as router (and converting between FDC3 versions as needed).
  • Desktop Bridging is also essentially the same thing - providing a sockets-based messaging protocol between different desktop agents.
  • At some level, Connectifi must be implementing a bus also.

@novavi
Copy link

novavi commented Jan 23, 2023

Hi @robmoffat thanks for raising this issue.

Related this this, on the point @kriswest raised (which you cited) about the possibility of using a 'vendor-agnostic FDC3 NPM module to detect and connect to API implementation(s)', I have something to share.

I have implemented this fdc3-installer library:

https://github.com/novavi/fdc3-installer

over the last few weeks. It aims to provide a solution to the problem in browser-based environments of tight coupling between FDC3-enabled apps and FDC3 Desktop Agents, by providing a mechanism to dynamically discover and install an agent within an app at runtime. This approach allows an app to run both in a desktop container (using the container's built-in agent) and also in a browser-based micro-frontend container (using a dynamically-installed agent) with zero code changes to the app. The library supports multiple strategies for the areas of agent discovery, creation and bootstrapping - with the ability to easily add and try out additional strategies based on any subsequent discussion / ideas.

The library does not claim to have all the answers by any means, but demonstrates some of the options that could potentially be used for a solution in this area. I hope this will help in the wider discussion that needs to be had within the FDC3 community about how we can best overcome the tight-coupling problem for browser-based FDC3 Desktop Agent implementations - and help move us towards standardized approach in the future.

I was originally aiming to publish this library more like sometime next month rather than now but after seeing that you'd raised the issue, I brought this forward in the interest of the discussion and just published what I have now. Because of this, I haven't actually even proof-read the stream-of-consciousness that I turned into a README yet, so parts of the description might still be a bit rough round the edges.

@kriswest
Copy link
Contributor

kriswest commented Jan 23, 2023 via email

@novavi
Copy link

novavi commented Jan 23, 2023 via email

@nkolba
Copy link
Contributor

nkolba commented Jan 23, 2023

@novavi - this is great work! Thanks for sharing.

Just want to note that this is a code project and exactly the kind of work that is vital to the ecosystem. It also underscores that there isn't anything missing from the standard to solve this problem. In fact, as @robmoffat alludes to, Connectifi already provides secure and seamless support across all environments including web and cross-origin in full conformance with the 1.2 spec.

Keeping the standard simple, accessible, and focused only on those problems that truly address interoperability is the best way to continue to drive adoption as well as the innovation of FDC3.

@kriswest
Copy link
Contributor

It also underscores that there isn't anything missing from the standard to solve this problem.

That is not the case @nkolba - it demonstrates that the problem, of establishing standardized ways of retrieving a reference to an API implementation, is solvable. It absolutely doesn't eliminate the need to adopt a standard for how to do so that app developers can write a single way of doing so/single version of their apps. Further, @novavi's write-up on it clearly indicates several areas that would specifically benefit from standardization, or already do, in order to reduce complexity for the app developer. These include the installation of the API reference into window.fdc3, all 3 of the discovery, creation and bootstrapping strategies and the use of internal & external provider directories.

If we don't provide a clear standardized approach we are not keeping the Standard simple or accessible - quite the opposite as application vendors will still have to choose approaches, configure for individual providers, test widely etc. and hence we again encourage the ecosystem to become fragmented and factional. Whereas, with a little work we can likely reduce complexity for app developers significantly, aiming for as close to zero configuration and variation in code as possible. That is quite obviously addressing problems that affect interoperability and ease of adoption, where attempting to block the community from doing so is not.

@nkolba
Copy link
Contributor

nkolba commented Jan 29, 2023

As discussed in the standards meeting last week, it may helpful to split this (and the previous email thread) into three separate topics:

  • Whether 1.2 Conformance tests should require FDC3 to be exposed as a global or if this should be optional (as the 1.2 spec states)
  • Whether the global requirement should be continued going forward in 2.x
  • What additional standards (if any) are needed for Web.

Note: while points 2 & 3 are somewhat related, the global issue doesn't just impact web. It is a blocker for conformance support on other tech stacks such as Java, .NET, Python, and many others and forces FDC3 conformance into a very specific type of implementation.

@kriswest
Copy link
Contributor

kriswest commented Jan 31, 2023 via email

@novavi
Copy link

novavi commented Feb 1, 2023

Just on the issue of the provision of the window.fdc3 global going forward, for the benefit of anyone reading this who didn't already see the separate (longer) 'FDC3 Desktop Agents vs. API implementations and using FDC3 on the Web' thread, I would like to reiterate here a few key points that I made as part of that discussion:

  • Regardless of one's views on making APIs available in the global scope in the general sense, providing the FDC3 API on the window.fdc3 object has the clear benefit of making all DAs consistent in terms of how they provide the API. Additionally, it's not too difficult to draw a distinction between an API that an application always imports for itself (e.g. like a grid or a utility library where it is always better to use the more modern module mechanism than to use a global) and an API which may well in a number of circumstances be pre-installed on behalf of the app by the container environment (e.g. in the case where an FDC3-enabled app optionally runs in a desktop container which provides a DA).
  • The fdc3Ready() function implementation in @finos/fdc3 uses the availability or non-availability of window.fdc3 when deciding whether to resolve or reject (https://github.com/finos/FDC3/blob/master/src/api/Methods.ts), so I believe changing the requirement around window.fdc3 would also imply a change to the behaviour of fdc3Ready().
  • window.fdc3 has a dual use. The first use is simply as a mechanism for an app to obtain a reference to the DA's FDC3 API. The second use, although less obvious, is actually very important – this is the use of the global as a mechanism for a standardized installer library (or even just app-level conditional logic) to determine whether a DA is already provided/pre-installed. If the FDC3 standard did move away from requiring DAs to be installed in window.fdc3 then there would probably need to be an agreed, standardized, new mechanism for desktop containers to provide a reference to their built-in DAs (and of course if that mechanism ended up just using a different global to provide a factory function or factory class, then the proposed change wouldn't be eliminating globals in the general sense - it would simply be removing one specific global).
  • Requiring a new way to discover whether a DA is already installed in an environment (in a newer version of the FDC3 standard) is further complicated by the fact that ISV apps would then need to worry about handling both the old (window.fdc3) and the new (as yet unspecified) mechanisms to test for a DA. This is because an app might need to run in existing versions of desktop containers (which support window.fdc3) and newer versions of those same desktop containers (which might support a different mechanism) and also have the ability to run in a browser by installing a browser-based DA.

Of course, there may be some valid counter-arguments to the ones I made above which could make a compelling case for the removal of the global from the standard (and which actually outweigh the disruption caused by the removal). I'd be interested to hear of any. The main one I can think of off the top of my head is if there was a requirement to install more than one DA in a given environment (although I believe this would go beyond what the current FDC3 spec provides for, and I would also have thought that any potential need to do that would likely be significantly undercut by the availability of a Desktop Agent bridge a.k.a. Backplane solution for interop between apps running in different ecosystems / containers that used different DAs).

For reference, the full 'FDC3 Desktop Agents vs. API implementations and using FDC3 on the Web' discussion thread I was referring to is here:
https://groups.google.com/a/finos.org/g/fdc3/c/jCvlLjokBLs

@kriswest
Copy link
Contributor

kriswest commented Feb 1, 2023

Great summary @novavi

@kriswest kriswest added the api FDC3 API Working Group label Feb 6, 2023
@kriswest
Copy link
Contributor

kriswest commented Feb 6, 2023

At the last FDC3 Standards Working Group meeting (#899) it was resolved that a discussion group should be set up to discuss what changes need to be made to how the FDC3 API is accessed, to enable its use in a Web browser (rather than a container or browser extension that makes the API available at window.fdc3).

This is currently only possible through the import of an implementation from a proprietary module (allowed, but not recommended in standard version <=1.2, but not in 2.0), which has significant downsides for the FDC3 ecosystem as it requires an application to be adapted for each desktop agent that it may be used with (which is not the case when working with an injected window.fdc3). A lively discussion of possible ways forwards, and their impacts on the FDC3 ecosystem has already started over email, which should continue in the discussion group.

To help us organise the discussion group at a time suitable for all those who wish to participate, please indicate your interest and dates you could attend below (by clicking on the relevant emojis):

  • 😄 Monday 13th Feb 11:30AM EST / 4:30PM GMT
  • 🎉 Wednesday 15th Feb 10AM EST / 3PM GMT
  • ❤️ Thursday 16th Feb 11AM EST / 4PM GMT
  • 👎 Nothing works I need other options!

Poll Closed: result:
image

@kriswest kriswest changed the title FDC3 For the Web FDC3 For Web browsers Feb 16, 2023
@novavi
Copy link

novavi commented Feb 16, 2023

Kris mentioned in the 'FDC3 for Web Browsers Discussion group' meeting today (#908) that people could raise here discussion points about the use of FDC3 in web browsers and/or points for the next meeting relating to any potential evolution of the standard.

I don't actually have any specific issues for the next meeting at this stage (I'm sure I'll think of something nearer to the time). But just to pick up on one point raised today about the alleged inability to use the postMessage API for native browser local cross-origin comms (sorry, I can't remember who mentioned it now). To be clear, postMessage API can in fact be used successfully for native browser local cross-origin cross-window interop.

The restriction in this case is that (unlike the same-origin-only Broadcast Channel API) postMessage API requires a target window reference and also (assuming you sensibly want to avoid reliance on asterisk wildcards for security purposes) a target window origin when posting messages. In the case of an iframe, it can perform limited discovery of sibling iframes because even though it can't access its container's DOM on a cross-origin basis, it can still use the container's window.frames collection on a cross-origin basis. However, even with those sibling window references, it cannot (to my knowledge) read the original or current location hrefs for those windows - or indeed discover the appIds of the apps currently running in those windows. Moreover, there's also the wider problem of interop with external tabs/windows - only the iframe which originally spawned the external tab/window would be able to directly interop with it (i.e. via the window reference returned by window.open() or by window.opener depending on the direction you're messaging) and anything that involved indirect interop by means of republishing messages across a chain of windows would obviously be too brittle to be worth considering - not least because one or more of the windows in the chain could be closed by the user at any time.

This all means that postMessage API can be used for cross-origin cross-window local interop, but that you simply need a solution to the above routing problem. One solution is to use some sort of lightweight 'hub' or 'router' in the original container window to help orchestrate things for the DAs in the app windows (e.g. route interop/channel messages, and open external windows on behalf of the iframe apps and track the references to those opened windows). One consequence of this approach (which is broadly what I used in a limited FDC3 DA implementation myself) is that it matters where a window is opened from. For example, if you opened an external window via the original container (i.e. an fdc3.open() invocation within an app window which delegated the actual window.open() to the parent container), then interop with the external window would work fine. But if you bookmarked that external window, closed it, and later reopened it - then you would have no interop because you'd have no window reference on either side.

In practice, I don't believe the extra hop via a 'hub' or 'router' in the container presents any problems for most real-world scenarios. Now, there might be some limited alternative solutions for peer-to-peer style iframe interop, perhaps involving some sort of handshaking to overcome the initial lack of visibility around the window hrefs (although I'm honestly not sure how you'd do this securely in a manner that would allow you to ever trust the other iframe window). The issue of peer-to-peer local interop with external windows seems intractable to me though - at least based on current browser APIs that I'm aware of . I'd actually be interested if anyone had any different patterns for cross-origin local messaging in general.

Anyway, the end result of all this is that for most real-world scenarios you could potentially use postMessage API for native browser local cross-origin interop - as long as you use a sensible approach for message routing. However, in the specific theoretical situation where FDC3 apps / windows were opened completely independently of each other (a so-called containerless scenario) you would then have to use a cloud-messaging WebSocket API approach, instead of being able to use a local-messaging postMessage API approach. And of course there are a few other scenarios where a cloud-based approach could achieve things that a local-based approach could not support e.g. direct interop with an app on a another device, without using a bridge.

@nkolba
Copy link
Contributor

nkolba commented Feb 16, 2023

thanks @novavi - this an excellent summary of what is feasible as well as the challenges with the client only approach to interop in the browser. The reproducibility of a URL and the controls around cross-origin trust are fundamental building blocks of the web and not wanting to break these patterns lead us (at Connectifi) to the cloud approach.

My thoughts post the meeting are pretty brief:

  • the window.fdc3 requirement is the only clearly identified issue with the spec relating to FDC3 in browser
  • removing the window.fdc3 as a MUST has no clear downside. In fact, this was just changed in 2.0, so all of the growth and interest we've seen in FDC3 for the past 5 years has happened without this being mandated. If the community prefers the global pattern, they are free to continue to use that pattern, while requiring the global clearly inhibits standard implementation options in browser and any other technology stacks.
  • open source code projects can definitely help here, but a mandate for a specific implementation/library as part of the standard would not be consistent with the principles of FDC3.

Looking forward to hearing from the rest of the community on this.

@novavi
Copy link

novavi commented Feb 17, 2023

thanks @nkolba - you raise a valid point about the reproducibility of a URL. It's certainly true that if a window with a given url behaved differently depending on where it was opened, this could cause confusion to end users. And I agree that a cloud-based approach certainly has the potential to eliminate that particular (undesirable) difference. Having said that - playing devil's advocate for a moment - one could argue that although ensuring reproducibility of a URL would be a good thing to aim for, it's possible that the cost might be paid in greater friction in non-federated identity scenarios, if a cloud-based approach ended up forcing an (undesirable) additional logon for the agent in the given app. This is something the user wouldn't see when opening the same app in either a desktop container or in a MFE container that used local interop. So it's possible that there could be trade-offs, depending on the specific setup of the institution and the ISVs involved. Of course, every setup is different - which is why I think a good result for the community would be to have a standard which encompassed all the common scenarios, and a range of solutions from agent providers to cater for those different scenarios.

I have to say that - based on my current knowledge of the FDC3 standard at least - I don't really agree with the assertion that removing the window.fdc3 as a MUST has no clear downside. I believe the downsides of removal would be the inability to use window.fdc3 to directly detect the presence of a pre-existing agent (in the case where a container-agnostic app could be run both in desktop containers and browser-based MFE containers) and also the fact that window.fdc3 is currently closely intertwined with the agent bootstrapping process and the standard fdc3Ready() behaviour. For these reasons, it seems to me that any removal would require (a) a new standardized mechanism for desktop containers to provide their FDC3 DAs (I've not yet heard anyone suggest what this could/should be); and (b) a change to the behaviour of fdc3Ready(). Point (b) in particular seems problematic for ISVs because an app that is expected to work across different FDC3 versions (e.g. where it only uses basic FDC3 functionality) could not easily adjust its usage of fdc3Ready() based on the version of the agent or version of FDC3. This is because the app shouldn't even be invoking fdc3.getInfo() to determine the version until after it has awaited fdc3Ready(). But the app also couldn't rely on fdc3Ready() if the behaviour depended on the version of FDC3. This feels like a chicken and egg situation - perhaps there's a way around it that's not clear to me at the time I write this. For reference, I also listed some of these points above (#896 (comment))

Now that I think about it, I've yet to actually see a convincing upside for any proposed removal of window.fdc3.

Firstly, I don't particularly buy into the argument that static import declarations are necessarily better in every circumstance just because they are the more modern ES way. To me, a DA feels like a different category of import than something like a UI component (where an import declaration would always definitely be better) in that it's an API that can be injected into the environment in the case of a desktop container. For me, this makes it more analogous to a polyfill for a new browser API which hasn't yet been made available in all browsers. Additionally, it's not clear to me that a static import declaration is a good method for loading an agent in any case (since import declarations can't be used in conditional blocks, this would imply either fixing to a single specific agent at build-time or alternatively including multiple agents in the resulting script bundle even though only one was required at runtime). That's actually what caused me to look at the idea of an installer library in the first place.

Secondly, I think I'd probably need some convincing that there's any significant downside to having the agent installed in a global (instead of inside part of the main app module) from a security perspective. In particular, having the agent hidden in the revealing module pattern or similar doesn't seem to offer any meaningful protection from being tampered with by malicious code. For example, if someone wanted to write malicious code to use as part of a XSS attack to read all inbound and outbound interop messages, it would actually be far easier to directly target the native browser APIs that the FDC3 DA relied upon (postMessage or WebSocket, to attack local or cloud interop approaches respectively) than to target the layer on top i.e. the multiple intent/channel methods of the FDC3 DA itself.

However, I can believe there could be some genuine upsides which I'm not fully aware of - so I'm definitely interested in hearing any other arguments on the matter.

As for the question of open source vs FDC3 standard in terms of the strategy for an installer library or similar, my main concern with an open source approach would be the risk of untested/unmaintained implementations and unnecessary duplication/fragmentation. To this I would also add the possibility of confusion in the case of smaller ISVs where the developer knowledge of FDC3 may not initially extend much further than their boss having mandated some work with a deadline and a simplistic "Get FDC3 done" slogan. More specifically, if you think about the combination of multiple open source agent installer implementations with (over time) different versions of the FDC3 spec and (as the market grows larger) multiple competing desktop containers and web-based agent providers, it could easily lead to smaller ISVs building apps that don't do a good job of installing an FDC3 DA. At best, this might mean the app not working reliably or consistently across different containers. At worst, this might risk an approach containing security flaws that would not be limited to that particular app i.e. which could potentially compromise the interop of the whole ecosystem / MFE container that the app was loaded into (even when all the other apps in the ecosystem had done the right thing). This is why I would argue in favour of having some form of installer library or equivalent mechanism as part of the FDC3 standard itself - where it can be agreed, designed, implemented, tested and maintained in a manner that promotes confidence in FDC3 as an open interop standard and enables growth in FDC3 adoption amongst ISVs and institutions. I appreciate that others might take a different view on this, so I'd also be interested to hear from the rest of the community.

@kriswest
Copy link
Contributor

kriswest commented Feb 20, 2023 via email

@kriswest
Copy link
Contributor

kriswest commented Feb 20, 2023 via email

@nkolba
Copy link
Contributor

nkolba commented Feb 20, 2023

FWIW I don't we're that far apart in what we're saying and I think we all agree that producing a common library is the best way forward. Perhaps the best course is to put the larger questions on the standard to the side for now and focus on that.

@kriswest
Copy link
Contributor

kriswest commented Feb 21, 2023 via email

@novavi
Copy link

novavi commented Feb 21, 2023

I assume we're talking about a common installer library here? If so, this sounds positive. I think to move forward it would be worth first defining clearly what should be in and out of scope for the initial focus on an installer library. Based on the discussion so far, there are many wider issues raised by the use of FDC3 in a browser-based environment which can probably be kept in mind but largely parked for discussion purposes (this includes the idea of running different agents in different apps, which was floated in the last meeting). So the idea of sub-dividing the standard as @kriswest suggested to allow an initial focus on API interface and methods of retrieving access to it seems sensible to me.

Clearly everyone will have their own views - and I'll be very interested to hear everyone else's - but in the meantime some of the things that spring to mind when I think about a common installer library now include:

  • Standardization of agent provision - the may be a common ground where a balance can be struck between allowing a few different approaches (and indeed enabling innovation) by agent vendors, and disallowing too much variation in how an agent can be provided. In particular, whilst it would theoretically be possible to support almost any agent delivery mechanism, I believe it would be better if there could be a degree of standardization around agent provision in the FDC3 spec (e.g. requirement for factory function, etc.) in order to reduce the need to support the relatively large number of approaches I laid out in the fdc3-installer library I put together previously.
  • Whether the installer library could/should be part of the existing npm package or a separate (new) package. There are pros and cons to both approaches. If it was part of the existing npm package, ISVs would potentially be including baggage they didn't need if all they required was the type defs (e.g. where they were only targeting a desktop container, and not browsers). The baggage would be mitigated by modern script bundlers, but this could still be suboptimal. Unless of course the future FDC3 standard actually required the use of a (lightweight) installer to obtain an agent in all circumstances (e.g. both for browsers and for desktop containers), in which case the answer here could be different.
  • Version handling. Specifically, should a given version of an installer be expected to handle installation of FDC3 DAs supporting different versions of the FDC3 spec (e.g. v1.2, v2.0, etc.) or should an installer be linked to a specific version of the standard? ISVs would benefit from the ability to write apps which run on different versions of an FDC3 DA (where they use API methods that are common across those versions). This would be consistent with how apps have historically been run on different browser versions using common APIs, and using graceful degradation where necessary. Additionally, the existing npm package includes the compareVersionNumbers and versionIsAtLeast functions, which implies the original intention was to allow an app to target more than one FDC3 DA version - allowing the app to make it's own decision on whether the DA provided at runtime is sufficient for the app or not. To achieve this, the installer library would presumably need to be a separate package.
  • window.fdc3 installation. I'm very conscious that there are different views on this, but for reasons mentioned previously (not just by me) it's inextricably linking with agent bootstrapping - which itself has to be considered by any installer. Therefore I'm not sure it's realistic to avoid or park this subject. Again, going back to the issues I looked at when I worked on the fdc3-installer idea, I somewhat sidestepped this area at the time. That library's installAgent() method actually returns the fdc3 object directly - which theoretically allows the app to use that fdc3 object (if the app wasn't using the wrapper functions from the @finos/fdc3 npm package, which ultimately delegates to the global window.fdc3 object). The main reason I sidestepped the issue was that I didn't believe an installer library could perform the window.fdc3 installation itself unless it was dealing with an an explicitly-bootstrapped DA (which goes beyond what the FDC3 spec provides for). Hence, the installer made the assumption that all agents (whether implicitly or explicitly bootstrapped) would be responsible for their own window.fdc3 installation, and that the installer library should not get involved. Clearly, if the discussion and design of any future common installer library meant that a different approach to global window.fdc3 installation was ultimately decided upon (with the backward compatibility support that any change implies) then whatever this new/different approach was would need to be factored into the design of the installer library (and of course also into the fdc3Ready function).
  • Detection of any existing FDC3 DA. Clearly this is related to the issue of window.fdc3 installation above. Clearly, any change to the requirement for window.fdc3 installation implies a new/different mechanism would need to be specified to allow an installer to detect any existing DA (and this mechanism would ultimately need to be provided in desktop containers also, as I have alluded to previously).
  • Passing config to agents. Unless an installer returned an fdc3 object which required an app to manually bootstrap it, then config would need to be provided at the installer level to use at agent construction/bootstrap time. Again with the fdc3-installer idea, I supported the concept of static config which could be defined in the JSON installer config file. This made sense to me at the time, because config options like window/tab preference for fdc3.open() behaviour or WebSockets urls or the like could be defined in a config file - and indeed would be better defined centrally at container-level config (where a container exists) for consistency and to reduce duplication across individual apps. However, I can now see that only having support for passing static values could be a severe limitation. In particular, if an agent allowed apps to pass callback functions to customise the behaviour e.g. for logging, Resolver UI, or anything else then limiting config to static values only would be unacceptable. To solve this, any method provided by an installer might need to also support the ability to accept a JS config object argument which would be passed through to the agent at construction/bootstrap time (e.g. passed straight through as a factory function argument or similar). There might even be a case for supporting both static installer-config-file-defined values and non-static JS objects that can be passed through - so perhaps this should be on the table for discussion?
  • Agent discovery. This relates to the so-called discovery strategies I defined in the fdc3-installer library. Some of the ones I laid out are problematic and potentially brittle (i.e. couldn't be used across all agents) and therefore could probably be ruled out after any serious discussion. Conversely, there could well be some better ideas for how an app can discover an agent at runtime. In any case, ISVs would benefit from having several different options available to them in order to support different MFE container scenarios - but by the same token, supporting too many different strategies could risk confusing ISVs and making an installer library harder to test and maintain.
  • CSP for DA module import. This should be designed-in. The safest, most restrictive option would presumably be to require apps to host agent implementations alongside the app's own script bundles (though this would place a burden on the deployment process for individual apps). This type of approach ought to mean that - from a security perspective - dynamic loading of a DA was not all that much different from lazy loading an app script bundle at runtime in a module federation scenario. But there any many different implementation options in this area, and therefore there is plenty to discuss and POC. Clearly for any common installer library to be used in a production environment, it would need to either only support the most secure method for obtaining a DA, or at the very least it would need to default to that option (and provide very clear console warnings if an app strayed from that recommended path).

I could go on further, but will just put the above thoughts forward for now. Look forward to discussing more in the next meeting.

@novavi
Copy link

novavi commented Feb 23, 2023

For the record, I should correct something that I mentioned in one of my recent posts about browser-based local interop above (#896 (comment)) where I stated that postMessage API requires a target window reference - and that this always imposes limitations around app launching and requires a common 'hub' or 'router' window for messaging.

I had originally ruled out Broadcast Channel API completely on the basis of the same-origin policy restriction it imposes. And since postMessage API is (as far as I am aware) the only native browser local messaging API that works for the cross-origin scenario (which is necessary in most real-world situations) I had thought that one would just have to live with the requirement for window references. In practice, that would mean apps delegating interop and window opening functionality to a 'hub' or 'router' running at the micro-frontend container level. Moreover, it would mean that if a user launched an app independently (i.e. in manually opening a separate window or tab, and navigating to the app's url) then that app could not participate in local interop.

However, with a bit of lateral thinking, I can now see that there is a fairly simple mechanism to overcome the above problem. This mechanism effectively provides for cross-origin interop between isolated independently-launched windows. The solution I came up with uses postMessage API in conjunction with Broadcast Channel API, and it works along the following lines:

  • app1 and app2 are both launched independently from each other in a containerless manner (i.e. neither of them spawn each other, and neither of them are spawned from a common container or launcher window).
  • app1's DA (let's say this is on port 3100) dynamically creates a hidden iframe pointing to a page containing some simple 'ancestor bridge' logic (let's say this iframe is on port 4000).
  • app2's DA (let's say this is on port 3200) also dynamically creates a hidden iframe pointing to another 'ancestor bridge' instance.
  • app1 (port 3100) can publish an interop message to app2 (port 3200) as follows - app1's DA uses postMessage API to publish the message to it's (child) ancestor bridge (port 4000) using the easily-obtained window reference to the hidden iframe, then app1's DA's ancestor bridge republishes the message to app2's DA's ancestor bridge using Broadcast Channel API (note that the two ancestor bridge instances are both running on port 4000, so the same-origin policy restriction imposed by Broadcast Channel API is satisfied).
  • app2's DA's ancestor bridge receives the message and uses postMessage API to republish the message to its (parent) app window (port 3200) using the easily-obtained window reference to provide the interop message to app2.

This goes further than I previously thought was possible with browser-based local interop. To be clear, based on a spike I just created, the above solution appears to work - but I have to confess I haven't (yet) tried it in anything beyond that limited spike.

Of course it's worth noting that for a local browser-based app to interop with a local desktop container or a remote (e.g. Citrix-based) container, then cloud-based interop is still absolutely necessary.

@kriswest
Copy link
Contributor

Of course it's worth noting that for a local browser-based app to interop with a local desktop container or a remote (e.g. Citrix-based) container, then cloud-based interop is still absolutely necessary.

@novavi This is a case a Desktop Agent Bridge could/would solve for (as a browser page could connect to local websocket).

@kriswest
Copy link
Contributor

7. You're introducing a race condition around who is setting window.fdc3 which otherwise wouldn't exist (probably the biggest problem).

No we're not as that race has to be specifically dealt with in step 1 (in any of the proposed options).

Apologies I didn't articulate that well at all. I had exactly the same initial reaction on my initial review of Step 1 Option 1 (Race) - and is why I personally think that it's not viable and we should try and ensure that there isn't a race. Thinking on it now, it might not be solvable for apps that have integrated the installer but then get run on an older container that sets the global up late, but for newer implementations at least I think we should at least amend the advice on when to set up the global to ASAP (with queuing if you need it). As step 2 can run in parallel (its likely to be mutually exclusive with step 1 use cases), this step 1 issue affects how quickly you can move on to step 3.

As apps can set the global themselves with a single line of code (and will rarely care about the above case), it (installer setting the global) doesn't matter to me all that much. I'll update the proposal to show that instead when I have a minute.

@kriswest
Copy link
Contributor

In the Desktop Agent Bridging PR we are having to add JSON Schema for all objects defined in the FDC3 API, which will then be referenced in the payloads defined in bridge message schemas. We intend to keep the two sets separate as far as possible as the API schema could be reused, for example in a postMessage based protocol for web containers.

In theory, we could switch to generating TypeScript types from these, however, quicktype sometimes generates non-ideal code (and can't build types with inheritance) so I'd recommend that we don't, instead picking up the burden of maintaining both the typescript types and schemas in parallel (which isn't all that hard once the original set have been created). It's also worth noting that quicktype seems to do a better job of going the other way and generating schema from the typescript...

@thorsent
Copy link

@nkolba I'm just getting a chance to look at the web portal code. Looks like it's along the lines that we discussed last meeting. I hope we can carve out time for you to walk the group through the project.. I haven't done a thorough review but have a little bit of initial technical feedback:

It looks like the handshake is implemented via an inbound request from opener -> child. I think there's a potential race here. It didn't look to me that browsers provide a reliable way of ensuring that a child receives a postMessage from a parent if the child sets up the listener after the fact (but I haven't experimented, perhaps Chrome is ahead of the spect, otherwise it may be necessary for the parent to poll, unless we can invent a scheme where the child posts back to the opener - though this can get complicated when there are multiple descendants).

Regarding detection of closed app boundaries - I think it would be reasonable to leave this requirement off, and out of the open-source implementation. There are probably several approaches that could be taken and vendors might choose to implement different types of reliability mods as value adds. I would be interested in the group's perspective.

@nkolba
Copy link
Contributor

nkolba commented Mar 30, 2023

thanks for the feedback @thorsent

Agree with the question of app boundaries, this is best left to the implementation layer. There may be a similar conclusion we reach on race condition strategy as well....

FYI: I will have a hard stop at 11:30 EST tomorrow - @kriswest - can we have any discussion on this in the first half of the meeting?

thanks.

++ @bschwinn

@kriswest
Copy link
Contributor

I think leaving the potential race unaddressed/for the implementation layer would be a mistake and very likely to cause issues and contention between desktop agent implementors.

Duly noted on the hard stop - however, I think we need to finish up what we were halfway through last time rather than jumping around. Reviewing another proposed implementation before we've agreed on requirements for one might be putting the cart before the horse.

I'm booked up before the meeting, but will post an agenda shortly and try to fit in a look myself beforehand today.

@kriswest
Copy link
Contributor

kriswest commented Mar 30, 2023

...and I firmly grasped the wrong end of the stick on which potential race was being discussed 😊 (I thought you meant the race between step 1 and 2, rather @thorsent noted a potential race within the step 2 parent/child messaging).

It bears discussion - and fortunately is right where we were in the proposal review (step 2). Hence, we could probably pick up there.

@robmoffat
Copy link
Member Author

So, first thing I wanted to document in here is based on chats I've had with @kriswest and @openfin-johans. I am starting to see the space we're in as a bit like the OSI stack. Recall in that different concerns are handled in different layers. I think we'd do well to adopt a similar approach here.

  • So, one layer of the stack is our JSON schema for FDC3 messages. The wire protocol.
  • A layer above this defines how these objects are sent around. This could be over postMessage for FDC3 on the Web, or Async API via WebSockets (in the case of Desktop Agent Bridging)
  • A third layer on this might define the application itself. For Desktop Agent Bridging this might be the port ranges, retry logic, config etc.

The main advantage of this is reuse. I see us being able to reuse a lot of this in different places if we modularise correctly.

@robmoffat
Copy link
Member Author

robmoffat commented Mar 31, 2023

A point that I didn't raise in the meeting yesterday was that I see a pattern emerging that I think we should make sure we exploit. Which is - when we consider Desktop Agent Bridging, what @nkolba is doing with Connectifi and what Pierre is after with as @kriswest calls it "Micro Frontend Container instance sharding" we end up with quite the hierarchy of contexts:

Untitled drawing

This implies to me that we should ensure that whatever abstractions we build work at any arbitrary layer of a hierarchy.

I am going to leave this here for other people to think about rather than try and fill out any details - I'm not proposing anything per se, just saying that this needs some thought.

@kriswest
Copy link
Contributor

kriswest commented Jul 5, 2023

The discussion group's working doc was migrated to Sharepoint from Google drive and can now be found here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api FDC3 API Working Group enhancement New feature or request FDC3 for Web Browsers
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants