# FDC3 Compliance

Source: https://docs.interop.io/browser/getting-started/fdc3-compliance/index.html

## Overview

[FDC3](https://fdc3.finos.org/) aims at developing specific protocols and classifications in order to advance the ability of desktop and web apps in financial workflows to interoperate in a plug-and-play fashion without prior bilateral agreements.

## FDC3 for io.Connect Browser

> ⚠️ *Note that **io.Connect Browser** and the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library support fully the FDC3 2.2 standards. This means that all FDC3 functionalities specified in the FDC3 standard will work out of the box when using the `@interopio/fdc3` library in your apps.*

The following sections describe only the specifics of running FDC3-compliant apps within **io.Connect Browser** and using the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library which provides an io.Connect implementation of the FDC3 standard. For more detailed information on the FDC3 standard and APIs, see the [official FDC3 documentation](https://fdc3.finos.org/docs/fdc3-intro).

## FDC3 Implementation

The [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library is the io.Connect implementation of the FDC3 standard.

### Referencing

To install the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library, execute the following command:

```cmd
npm install @interopio/fdc3
```

Reference the library in your app:

```javascript
import "@interopio/fdc3";
```

You can also reference it as a script from UNPKG:

```html
<script src="https://unpkg.com/@interopio/fdc3@latest/dist/fdc3.umd.js"></script>
```

### Initialization

The [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library can be used only in interop-enabled io.Connect apps - either a [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) with initialized [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library, or a [Browser Client](https://docs.interop.io/browser/developers/browser-client/overview/index.md) app with initialized [`@interopio/browser`](https://www.npmjs.com/package/@interopio/browser) library. To be able to use functionalities related to the io.Connect [Channels](https://docs.interop.io/browser/capabilities/data-sharing/channels/index.md) and the [FDC3 User Channels](https://fdc3.finos.org/docs/api/spec#types-of-channel), the Main app must be initialized with properly defined Channels (see the [Channels](#channels) section).

Initializing the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library in the Main app:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";
import "@interopio/fdc3";

const channels = {
	definitions: [
	    {
	        name: "Red",
	        meta: {
	            color: "red",
	            fdc3: {
	                id: "fdc3.channel.1",
	                displayMetadata: {
	                  name: "Channel 1",
	                  glyph: "1"
	                }
	            }
	        }
	    }
        // You can define as many io.Connect Channels as you need and map them
        // to the default FDC3 User Channels if you want to use them as such.
        // For more io.Connect Channel definitions and mappings, see the "Channels" section.
	]
};

const config = {
    licenseKey: "my-license-key",
    channels
};

const { io } = await IOBrowserPlatform(config);

// The FDC3 API will now be available as an `fdc3` object injected in the global `window` object.
const info = await fdc3.getInfo();

console.log(`FDC3 provider: ${info.provider}, FDC3 version: ${info.fdc3Version}`);
```

Initializing the `@interopio/fdc3` library in a Browser Client app:

```javascript
import IOBrowser from "@interopio/browser";
import "@interopio/fdc3";

const io = await IOBrowser();

// The FDC3 API will now be available as an `fdc3` object injected in the global `window` object.
const info = await fdc3.getInfo();

console.log(`FDC3 provider: ${info.provider}, FDC3 version: ${info.fdc3Version}`);
```

After the `@interopio/fdc3` library has been imported and the respective io.Connect library properly initialized, the FDC3 API will be available as an `fdc3` object injected in the global `window` object:

```javascript
const contextType = "Contact";
const handler = context => console.log(`Context: ${JSON.stringify(context)}`);

await fdc3.addContextListener(contextType, handler);
```

### FDC3 Web Connection Protocol

Available since io.Connect Browser 4.0

The recommended method for acquiring access to the FDC3 API in your FDC3 apps that are part of an **io.Connect Browser** project is to use the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library.

If your apps, however, are using the [`@finos/fdc3`](https://www.npmjs.com/package/@finos/fdc3) library instead, it's still possible to integrate them with **io.Connect Browser** as the platform provides internal support for the [FDC3 Web Connection Protocol](https://fdc3.finos.org/docs/api/specs/webConnectionProtocol). The support for this protocol enables FDC3 client apps to use the [`getAgent()`](https://fdc3.finos.org/docs/api/ref/GetAgent) method to acquire a `DesktopAgent` instance and access the FDC3 API.

Available since io.Connect Browser 4.2

The io.Connect support for the FDC3 Web Connection Protocol enables you to use the built-in Intent Resolver provided by the `@finos/fdc3` library.

## App Definition

To use your FDC3-compliant app in **io.Connect Browser**, you must either create an io.Connect [app definition](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions) for it, or place your already existing FDC3 app definition in any **io.Connect Browser** app store (local, remote, in-memory, or **io.Manager**).

### io.Connect Definitions

The following example demonstrates providing a minimal io.Connect definition for an interop-enabled app when initializing the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    applications: {
        local: [
            {
                name: "my-app",
                type: "window",
                title: "My App",
                details: {
                    url: "https://my-domain.com/my-app"
                }
            }
        ]
    }
};

const { io } = await IOBrowserPlatform(config);
```

The `name`, `type` and `url` properties are required and `type` must be set to `"window"`. The `url` property points to the location of the web app.

> ℹ️ *For more information on configuring your apps for **io.Connect Browser**, see the [Capabilities > App Management > App Definitions](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions) section.*

### FDC3 Definitions

**io.Connect Browser** supports the FDC3 app definition standard ([App Directory](https://fdc3.finos.org/docs/app-directory/overview) or AppD). FDC3 definitions are automatically converted to io.Connect ones, preserving the original FDC3 app definition in a top-level `fdc3` property added to the resulting io.Connect app [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) object. You can add FDC3 definitions from any supported **io.Connect Browser** [app store](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions): local, remote, in-memory, or **io.Manager**.

If you already have an FDC3 definition for your app, you can use the `"ioConnect"` property of the `"hostManifests"` top-level key to provide any app settings specific to the io.Connect framework that you want to employ:

```json
{
    "appId": "my-app",
    "title": "My App",
    "type": "web",
    "details": {
        "url": "https://example.com/my-app"
    },
    "hostManifests": {
        "ioConnect": {
            "name": "my-app",
            "type": "window",
            "details": {
                "url": "https://example.com/my-app",

            },
            "customProperties": {
                "includeInWorkspaces": true
            }
        }
    }
}
```

> ℹ️ *For more details on the FDC3 app definition standards, see the [FDC3 Application](https://fdc3.finos.org/schemas/2.0/app-directory#tag/Application) schema.*

## App Directory

The goal of the [FDC3 App Directory](https://fdc3.finos.org/docs/app-directory/overview) (or AppD) REST service is to provide trusted identity for apps. App definitions are provided by one or more App Directory REST services where user entitlements and security can also be handled.

**io.Connect Browser** supports the FDC3 app definition standard. FDC3 definitions are automatically converted to io.Connect ones, preserving the original FDC3 app definition in a top-level `fdc3` property added to the resulting io.Connect app [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) object. You can add FDC3 definitions from any supported **io.Connect Browser** [app store](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions): local, remote, in-memory, or **io.Manager**.

> ℹ️ *For more details on the FDC3 app definition standards, see the [FDC3 Application](https://fdc3.finos.org/schemas/2.0/app-directory#tag/Application) schema.*

The following example demonstrates how to configure **io.Connect Browser** to retrieve FDC3 app definitions from a [remote app store](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions-remote). Use the `remote` property of the `applications` object in the configuration object for the initializing the [Main app](https://docs.interop.io/browser/developers/browser-platform/setup/index.md#configuration):

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    applications: {
        remote: {
            url: "https://my-app-store.com/apps/",
            pollingInterval: 1000,
            requestTimeout: 5000
        }
    }
};

const { io } = await IOBrowserPlatform(config);
```

> ℹ️ *For more details on defining apps and configuring all supported app stores, see the [Capabilities > App Management > App Definitions](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions) section.*

> ⚠️ *Note that any app can connect to remote sources and not only the Main app. The app definitions from all remote sources are then merged by the Main app. The remote sources can supply both io.Connect and FDC3 app definitions. The only requirement for an FDC3 app definition to be usable in **io.Connect Browser** is to have a valid URL specified.*

According to the [FDC3 App Directory](https://fdc3.finos.org/schemas/2.0/app-directory) specifications, the remote store must return app definitions in the following response shape:

```json
{
    "applications": [
        // List of app definition objects.
        {}, {}
    ]
}
```

> ℹ️ *For more details on using App Directory, see the [FDC3 App Directory](https://fdc3.finos.org/docs/app-directory/overview) documentation.*

## Intents

The [FDC3 Intents](https://fdc3.finos.org/docs/intents/spec) concept serves the purpose of enabling the creation of cross-app workflows on the desktop. An Intent specifies what action the app can execute and with what data structure it can work. An app declares itself as an Intent handler via configuration or dynamically. Other apps can raise this Intent and provide context data for handling the Intent to the Intent handler app.

> ⚠️ *Note that the io.Connect framework provides its own [Intents API](https://docs.interop.io/browser/capabilities/data-sharing/intents/overview/index.md) implementation which fully supports interoperability with FDC3-compliant apps.*

Intents can be defined both in the `intents` top-level key of an io.Connect [app definition](https://docs.interop.io/browser/capabilities/app-management/index.md#app_definitions) object, or in the `"intents"` property of the `"interop"` top-level key in an [FDC3 app definition](https://fdc3.finos.org/schemas/2.0/app-directory#tag/Application).

The following example demonstrates how to define an Intent in an io.Connect app definition:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    applications: {
        local: [
            {
                name: "Instrument Chart",
                details: {
                    url: "http://localhost:4242/chart"
                },
                // Intent definitions.
                intents: [
                    {
                        name: "ViewChart",
                        displayName: "Instrument Chart",
                        contexts: ["Instrument"]
                    }
                ]
            }
        ]
    }
};

const { io } = await IOBrowserPlatform(config);
```

| Property | Type | Description |
|----------|------|-------------|
| `contexts` | `string[]` | The type of predefined data structures with which the app can work (see [FDC3 Contexts](https://fdc3.finos.org/docs/context/spec)). |
| `name` | `string` | **Required.** The name of the Intent. |
| `displayName` | `string` | The display name of the Intent. Can be used in UI elements to visualize the Intent. |

The Intent Resolver UI app allows users to choose an app for handling a raised [Intent](https://docs.interop.io/browser/capabilities/data-sharing/intents/overview/index.md):

![Intent Resolver](https://docs.interop.io/browser/images/intents/intent-resolver.png)

> ℹ️ *For more details on how to enable or disable the Intent Resolver UI, or on how to create your own custom Intent Resolver App, see the [Capabilities > Data Sharing > Intents > Intent Resolver](https://docs.interop.io/browser/capabilities/data-sharing/intents/overview/index.md#intent_resolver) section.*

> ℹ️ *For more details on using Intents, see the [FDC3 Intents API](https://fdc3.finos.org/docs/intents/spec).*

## Channels

The io.Connect [Channels](https://docs.interop.io/browser/capabilities/data-sharing/channels/index.md) correspond to the [FDC3 User Channels](https://fdc3.finos.org/docs/api/spec#types-of-channel). Channels are well-known named context objects that can be represented with colors and names in the UI of an app. They can be controlled programmatically or manually by end users directly from the app UI. This allows users to switch apps from one Channel to another, changing the context data with which they operate. All apps on the same Channel have access to the Channel context and can read or update the data in it as necessary.

To define system Channels, use the `channels` property of the configuration object for initializing the [Main app](https://docs.interop.io/browser/developers/browser-platform/setup/index.md#configuration). Use the following configuration to create io.Connect Channels mapped to the [default FDC3 User Channels](https://fdc3.finos.org/docs/api/spec#recommended-user-channel-set):

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const channels = {
	definitions: [
	    {
	        name: "Red",
	        meta: {
	            color: "red",
	            fdc3: {
	                id: "fdc3.channel.1",
	                displayMetadata: {
	                  name: "Channel 1",
	                  glyph: "1"
	                }
	            }
	        }
	    },
		{
	        name: "Orange",
	        meta: {
	            color: "#fa5a28",
	            fdc3: {
	                id: "fdc3.channel.2",
	                displayMetadata: {
	                    name: "Channel 2",
	                    glyph: "2"
	                }
	            }
	        }
	    },
	    {
	        name: "Yellow",
	        meta: {
	            color: "#FFE733",
	            fdc3: {
	                id: "fdc3.channel.3",
	                displayMetadata: {
	                    name: "Channel 3",
	                    glyph: "3"
	                }
	            }
	        }
	    },
	    {
	        name: "Green",
	        meta: {
	            color: "green",
	            fdc3: {
	                id: "fdc3.channel.4",
	                displayMetadata: {
	                    name: "Channel 4",
	                    glyph: "4"
	                }
	            }
	        }
	    },
	    {
	        name: "Cyan",
	        meta: {
	            color: "#80f3ff",
	            fdc3: {
	                id: "fdc3.channel.5",
	                displayMetadata: {
	                    name: "Channel 5",
	                    glyph: "5"
	                }
	            }
	        }
	    }
	    {
	        name: "Blue",
	        meta: {
	            fdc3: {
	                id: "fdc3.channel.6",
	                displayMetadata: {
	                    name:"Channel 6",
	                    glyph: "6"
	                }
	            }
	        }
	    },
	    {
	        name: "Magenta",
	        meta: {
	            color: "#cc338b",
	            fdc3:   {
	                id: "fdc3.channel.7",
	                displayMetadata: {
	                    name: "Channel 7",
	                    glyph: "7"
	                }
	            }
	        }
	    },
	    {
	        name: "Purple",
	        meta: {
	            color: "#c873ff",
	            fdc3: {
	                id: "fdc3.channel.8",
	                displayMetadata: {
	                    name: "Channel 8",
	                    glyph: "8"
	                }
	            }
	        }
	    }
	]
};

const config = {
    licenseKey: "my-license-key",
    channels
};

const { io } = await IOBrowserPlatform(config);
```

> ℹ️ *For more details on defining Channels, see the [Capabilities > Data Sharing > Channels](https://docs.interop.io/browser/capabilities/data-sharing/channels/index.md#defining_channels) section.*

Any custom Channel you define must be mapped to an FDC3 User Channel if you want to use it as such.

The [`@interopio/widget`](https://www.npmjs.com/package/@interopio/widget) library enables you to add the [io.Connect widget](https://docs.interop.io/browser/capabilities/widget/index.md) to your apps. The widget contains a fully functional Channel Selector UI which enables users to control Channels manually.

> ℹ️ *For more details on using the io.Connect widget, see the [Capabilities > Widget](https://docs.interop.io/browser/capabilities/widget/index.md) section.*

> ℹ️ *For more details on using User Channels, see the [FDC3 User Channels API](https://fdc3.finos.org/docs/api/ref/Channel).*

> ⚠️ *Note that the [`@interopio/fdc3`](https://www.npmjs.com/package/@interopio/fdc3) library supports all types of FDC3 Channels - User Channels, App Channels, and Private Channels.*

### Using FDC3 Contexts in Non-FDC3 Apps

Available since io.Connect Browser 3.4

If you have non-FDC3 interop-enabled apps, they can still use the contexts of FDC3 User Channels via the io.Connect [Channels](https://docs.interop.io/browser/capabilities/data-sharing/channels/index.md) API in order to retrieve, subscribe for, and publish FDC3 context data.

#### Retrieving FDC3 Context Data

The [`ChannelContext`](https://docs.interop.io/browser/reference/javascript/channels/channelcontext/index.md) object utilized by the Channels API methods for retrieving Channel contexts (such as [`get()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-get), [`getMy()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-getMy) and [`list()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-list)) will contain an `fdc3` property in its `data` object if FDC3 context data has been published to the Channel. The `fdc3` property is an object with a required `type` property holding the type of the FDC3 context:

```javascript
const context = await io.channels.get("Red");

// If FDC3 context data has been published to the Channel, the Channel context will contain a `data.fdc3` property.
if (context.data.fdc3) {
    // The `type` property of the `fdc3` object is required.
    const contextType = context.data.fdc3.type;

    console.log(contextType);
};
```

The [`get()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-get) and [`getMy()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-getMy) accept an [`FDC3Options`](https://docs.interop.io/browser/reference/javascript/channels/fdc3options/index.md) object as an optional argument. You can use this argument to specify the type of the FDC3 context in which you are interested. The methods will resolve with an empty object if FDC3 context data of the specified type isn't available in the Channel:

```javascript
// Specifying the type of an FDC3 context.
const fdc3Options = { contextType: "fdc3.contact" };

// Retrieving an FDC3 context of a specific type.
const fdc3Context = await io.channels.getMy(fdc3Options);
```

#### Subscribing for FDC3 Context Data

The object argument received by the handler provided to the [`subscribe()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-subscribe) or [`subscribeFor()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-subscribeFor) methods of the Channels API will contain an `fdc3` property if FDC3 context data has been published to the Channel to which you have subscribed. The `fdc3` property is an object with a required `type` property holding the type of the FDC3 context:

```javascript
// The `data` argument received by the callback will have an `fdc3` property
// if FDC3 context data has been published to the Channel.
const handler = (data) => {
    if (data.fdc3) {
        // The `type` property of the `fdc3` object is required.
        const contextType = data.fdc3.type;

        console.log(contextType);
    };
};

const unsubscribe = io.channels.subscribe(handler);
```

The [`subscribe()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-subscribe) and [`subscribeFor()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-subscribeFor) methods accept an [`FDC3Options`](https://docs.interop.io/browser/reference/javascript/channels/fdc3options/index.md) object as an optional argument. You can use this argument to specify the type of the FDC3 context in which you are interested. The callback passed to the `subscribe()` and `subscribeFor()` methods won't be invoked unless FDC3 context data of the specified type is published in the Channel:

```javascript
// Specifying the type of an FDC3 context.
const fdc3Options = { contextType: "fdc3.contact" };

// Subscribing to an FDC3 context of a specific type.
const handler = (data) => {
    // The `type` property of the `fdc3` object is required.
    const contextType = data.fdc3.type;
    console.log(contextType);
};

const unsubscribe = io.channels.subscribe(handler, fdc3Options);
```

#### Publishing FDC3 Context Data

The [`publish()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-publish) method of the Channels API accepts also a [`PublishOptions`](https://docs.interop.io/browser/reference/javascript/channels/publishoptions/index.md) object as a second optional argument. You can use it to specify the name of the Channel to update and whether the published data is an FDC3 context:

```javascript
// FDC3 context data to publish.
const data = {
    type: "fdc3.contact",
    name: "John Doe",
    id: {
        email: "john.doe@example.com"
    }
};

const options = {
    name: "Red",
    // Specify that the published data is FDC3 context data.
    fdc3: true
};

await io.channels.publish(data, options);
```

#### Adding FDC3 User Channels

Available since io.Connect Browser 4.0

To add FDC3 User Channels dynamically, use the `fdc3` property of the `meta` object in the [`ChannelDefinition`](https://docs.interop.io/browser/reference/javascript/channels/channeldefinition/index.md) object passed as an argument to the [`add()`](https://docs.interop.io/browser/reference/javascript/channels/api/index.md#API-add) method of the Channels API:

```javascript
// io.Connect Channel definition.
const channelDefinition = {
    // It's required to specify a name and color for the Channel
    // when adding Channels via the io.Connect API.
    name: "Black",
    meta: {
        color: "black",
        // FDC3 User Channel definition.
        fdc3: {
            // It's required to provide an ID for the FDC3 User Channel.
            id: "fdc3.channel.9"
        }
    }
};

const channel = await io.channels.add(channelDefinition);
```

### Using Multiple Channels

Available since io.Connect Browser 3.5

**io.Connect Browser** provides experimental support for working with multiple Channels simultaneously.

> ℹ️ *For more details on how to enable using multiple Channels and the considerations you should take into account, see the [Capabilities > Data Sharing > Channels > Channel Mode](https://docs.interop.io/browser/capabilities/data-sharing/channels/index.md#channel_mode) section.*

The FDC3 standard doesn't provide out-of-the-box support for multiple Channels. To enable FDC3 apps to work with multiple Channels, the io.Connect JavaScript [FDC3 implementation](#fdc3_implementation) has been extended with the following supplementary methods:

```javascript
// Retrieving all currently joined Channels.
const currentChannels = await fdc3.getCurrentChannels();

// Leaving a Channel by specified Channel ID.
await fdc3.leave("Red");

// Leaving all currently joined Channels.
await fdc3.leaveCurrentChannels();
```

The handler passed to the [`addContextListener()`](https://fdc3.finos.org/docs/api/ref/DesktopAgent#addcontextlistener) method receives as a third optional argument a Channel ID. You can use it to determine the Channel from which comes the context update:

```javascript
const contextType = "Contact";
const handler = (context, metadata, channelId) => {
    console.log(`Received updates from Channel ${channelId}.`);
};

await fdc3.addContextListener(contextType, handler);
```
