# App Management

Source: https://docs.interop.io/browser/capabilities/app-management/index.html

## Overview

The App Management API provides a way to manage **io.Connect Browser** apps. It offers abstractions for:

- *Application* - a web app as a logical entity, registered in **io.Connect Browser** with some metadata (name, title, version, etc.) and with all the configuration needed to spawn one or more instances of it. The App Management API provides facilities for retrieving app metadata and for detecting when an app has been added or removed.

- *Instance* - a running copy of a web app hosted in an io.Connect Window. The App Management API provides facilities for starting and stopping app instances and tracking app and instance related events.

The App Management API is accessible via the [`io.appManager`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md) object.

The [Live Examples](#live_examples) section demonstrates using the App Management API.

## App Definitions

To participate in the App Management API, each app in an **io.Connect Browser** project must have an app definition. App definitions are supplied using the `applications` property of the configuration object for initializing the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library in the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md). App definitions can be supplied locally or fetched from a remote source (custom REST service or [**io.Manager**](https://docs.interop.io/browser/capabilities/manager/index.md)).

> ⚠️ *Note that **io.Connect Browser** supports both io.Connect and [FDC3 app definitions](https://fdc3.finos.org/schemas/2.0/app-directory#tag/Application). The only requirement for an FDC3 app definition to be usable in **io.Connect Browser** is to have a valid URL specified.*

> ℹ️ *For a reference implementation of a remote app definitions store, see the [Node.js REST Config](https://github.com/InteropIO/rest-config-example-node-js) example.*

### Local

To supply local app definitions to the Main app, use the `local` property of the `applications` object and provide an array of app [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) objects.

The following example demonstrates defining two apps:

```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"
                }
            },
            {
                name: "my-other-app",
                type: "window",
                title: "My Other App",
                details: {
                    url: "https://my-domain.com/my-other-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.

### Remote

To supply app definitions from a remote location, use the `remote` property of the `applications` object and provide details for the remote app store:

```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);
```

The `remote` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `cache` | `object` | Settings for caching the app definitions. *Available since **io.Connect Browser** 4.1.* |
| `customHeaders` | `object` | Object containing key/value pairs of headers that will be appended to every request to the remote store. |
| `getRequestInit` | `function` | Function that must return a [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) object. This object will be merged with the default one and will be appended to every request sent to the remote store. Use this to provide custom request options or to override the default ones. *Available since **io.Connect Browser** 3.5.* |
| `pollingInterval` | `number` | Interval in milliseconds at which to poll the remote store for updates. If not provided, the platform will fetch the app definitions only once on startup. Defaults to `0`. |
| `requestTimeout` | `number` | Interval in milliseconds to wait for a response to the request for fetching app definitions from the remote store. Defaults to `30000`. |
| `url` | `string` | **Required.** URL pointing to the remote store. The remote store must follow the [FDC3 App Directory standard](https://fdc3.finos.org/docs/app-directory/spec). The provided apps must be of type [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) or `FDC3Definition`. |
| `waitInitialResponse` | `boolean` | If `true` (default), the platform will wait for an initial response before proceeding with the platform initialization. In case of an error or no response within the specified request timeout, the platform won't initialize. *Available since **io.Connect Browser** 4.1.* |

The `cache` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `enabled` | `boolean` | If `true`, the retrieved app definitions will be cached by using the browser `IndexedDB` API and the cached app definitions will be returned as a response to any API calls. If caching is enabled, you must also set the `pollingInterval` property to instruct the platform at what interval to retrieve app definitions from the remote store. Defaults to `false`. |

The remote store must return app definitions in the following response shape:

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

> ℹ️ *For more details on how to configure **io.Connect Browser** to connect to **io.Manager**, see the [io.Manager](https://docs.interop.io/browser/capabilities/manager/index.md) section.*

## Managing App Definitions Dynamically

App definitions can be imported, exported, and removed dynamically by using the [`InMemory`](https://docs.interop.io/browser/reference/javascript/app%20management/inmemory/index.md) object of the App Management API.

> ⚠️ *Note that all app [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) objects provided dynamically are stored in-memory and the methods of the `InMemory` object operate only on them - i.e., the app definitions provided during the initialization of the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library aren't affected.*

### Import

To import a list of app definitions dynamically, use the [`import()`](https://docs.interop.io/browser/reference/javascript/app%20management/inmemory/index.md#InMemory-import) method:

```javascript
const definitions = {
    {
        name: "my-app",
        type: "window",
        title: "My App",
        details: {
            url: "https://my-domain.com/my-app"
        }
    },
    {
        name: "my-other-app",
        type: "window",
        title: "My Other App",
        details: {
            url: "https://my-domain.com/my-other-app"
        }
    }
};
const mode = "merge";
const importResult = await io.appManager.inMemory.import(definitions, mode);
```

The `import()` method accepts a list of [`Definition`](https://docs.interop.io/browser/reference/javascript/app%20management/definition/index.md) objects as a first parameter and an import mode as a second. There are two import modes - `"replace"` (default) and `"merge"`. Using `"replace"` will replace all existing in-memory definitions with the provided ones, while using `"merge"` will merge the existing ones with the provided ones, replacing the app definitions with the same name. Use the `imported` property of the returned [`ImportResult`](https://docs.interop.io/browser/reference/javascript/app%20management/importresult/index.md) object to see a list of the successfully imported definitions and its `errors` property to see a list of the errors:

```javascript
const importedApps = importResult.imported;
const errors = importResult.errors;

importedApps.forEach(console.log);
errors.forEach(e => console.log(`App: ${e.app}, Error: ${e.error}`));
```

### Export

To export a list of already imported in-memory app definitions, use the [`export()`](https://docs.interop.io/browser/reference/javascript/app%20management/inmemory/index.md#InMemory-export) method:

```javascript
const definitions = await io.appManager.inMemory.export();
```

### Remove

To remove a specific in-memory app definition, use the [`remove()`](https://docs.interop.io/browser/reference/javascript/app%20management/inmemory/index.md#InMemory-remove) method and provide the app name:

```javascript
await io.appManager.inMemory.remove("my-app");
```

### Clear

To clear all imported in-memory definitions, use the [`clear()`](https://docs.interop.io/browser/reference/javascript/app%20management/inmemory/index.md#InMemory-clear) method:

```javascript
await io.appManager.inMemory.clear();
```

## Apps

### Listing Apps

To see a list of all apps available to the current user, use the [`applications()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-applications) method:

```javascript
const applications = io.appManager.applications();
```

### Specific App

To get a reference to a specific app, use the [`application()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-application) method and pass the name of the app as an argument:

```javascript
const app = io.appManager.application("ClientList");
```

### Retrieving App Definitions

Available since io.Connect Browser 4.3

To retrieve the full [app definition](#app_definitions) of an app, use the [`getConfiguration()`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md#Application-getConfiguration) method of the [`Application`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md) object:

```javascript
const app = io.appManager.application("my-app");

const definition = await app.getConfiguration();

console.log(`Retrieved definition for app "${definition.name}".`);
```

### Starting Apps

To start an app, use the [`start()`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md#Application-start) method of the [`Application`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md) object:

```javascript
const myApp = io.appManager.application("my-app");

const myAppInstance  = await myApp.start();
```

The `start()` method accepts two optional arguments - a context object (object in which you can pass custom data to your app) and an [`ApplicationStartOptions`](https://docs.interop.io/browser/reference/javascript/app%20management/applicationstartoptions/index.md) object:

```javascript
const myApp = io.appManager.application("my-app");
const context = { selectedUser: 2 };
const startOptions = { height: 400, width: 500 };

const myAppInstance  = await myApp.start(context, startOptions);
```

If you want to start an app that has an app definition, but that isn't interop-enabled (doesn't initialize the io.Connect library), set the `waitForAGMReady` property in the [`ApplicationStartOptions`](https://docs.interop.io/browser/reference/javascript/app%20management/applicationstartoptions/index.md) object to `false`. Otherwise, the io.Connect library will assume that you are trying to start an interop-enabled app and will wait for it to initialize its io.Connect API instance and connect properly to the io.Connect framework. This will lead to a timeout and your app won't be started.

The following example demonstrates how to start an app that isn't interop-enabled:

```javascript
const myApp = io.appManager.application("MyNonInteropEnabledApp");
const startOptions = { waitForAGMReady: false };

const myAppInstance = await myApp.start(null, startOptions);
```

## App Instances

### Listing Running Instances

To list all running instances of all apps, use the [`instances()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-instances) method:

```javascript
// Returns a collection of the running instances of all apps.
const allInstances = io.appManager.instances();
```

The `instances()` method returns a list of [`Instance`](https://docs.interop.io/browser/reference/javascript/app%20management/instance/index.md) objects describing the currently running instances of all apps.

### Current App Instance

To get a reference to the instance of the current app, use the `myInstance` property:

```javascript
const myInstance = io.appManager.myInstance;
```

### Stopping Instances

To stop a running instance, use the [`stop()`](https://docs.interop.io/browser/reference/javascript/app%20management/instance/index.md#Instance-stop) method of an instance object:

```javascript
await appInstance.stop();
```

## Events

### App Events

The set of apps defined for the current user can be modified dynamically. To track the events which fire when an app has been added, removed or updated, use the respective methods exposed by the App Management API.

App added event:

```javascript
const handler = app => console.log(app.name);

// Notifies you when an app has been added.
const unsubscribe = io.appManager.onAppAdded(handler);
```

App removed event:

```javascript
const handler = app => console.log(app.name);

// Notifies you when an app has been removed.
const unsubscribe = io.appManager.onAppRemoved(handler);
```

App updated event:

```javascript
const handler = app => console.log(app.name);

// Notifies you when an app definition has been updated.
const unsubscribe = io.appManager.onAppChanged(handler);
```

### Instance Events

To monitor instance related events globally (for all instances of all apps running in **io.Connect Browser**) or on an app level (only instances of a specific app), use the respective methods exposed by the App Management API.

#### Global

The [`appManager`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md) object offers methods which you can use to monitor instance events for all apps running in **io.Connect Browser**. Get notified when an app instance has started, stopped, has been updated or when starting an app instance has failed. The methods for handling instance events receive a callback as an argument which in turn receives the app instance as an argument. All methods return an unsubscribe function - use it to stop receiving notifications about instance events.

Instance started event:

```javascript
const handler = instance => console.log(instance.id);

const unsubscribe = io.appManager.onInstanceStarted(handler);
```

Instance stopped event:

```javascript
const handler = instance => console.log(instance.id);

const unsubscribe = io.appManager.onInstanceStopped(handler);
```

#### App Level

To monitor instance events on an app level, use the methods offered by the [`Application`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md) object. The methods for handling instance events receive a callback as an argument which in turn receives the app instance as an argument.

Instance started event:

```javascript
const myApp = io.appManager.application("my-app");
const handler = instance => console.log(instance.id);

myApp.onInstanceStarted(handler);
```

Instance stopped event:

```javascript
const myApp = io.appManager.application("my-app");
const handler = instance => console.log(instance.id);

myApp.onInstanceStopped(handler);
```

## Live Examples

### Handling Apps, App and Instance Events

App A demonstrates how to discover the available app definitions using the [`applications()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-applications) method of the App Management API. It also allows you to start the apps using the [`start()`](https://docs.interop.io/browser/reference/javascript/app%20management/application/index.md#Application-start) method of the app object. Additionally, it lists all instances of running apps and allows you to stop them using the [`stop()`](https://docs.interop.io/browser/reference/javascript/app%20management/instance/index.md#Instance-stop) method of the instance object.

App B is subscribed for the [`onInstanceStarted()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-onInstanceStarted) and [`onInstanceStopped()`](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md#API-onInstanceStopped) events and logs when an instance has been started or stopped.

<div class="d-flex">
    <iframe src="https://v0fys.csb.app/" style="border: none;"></iframe>
</div>

## API Reference

For a complete list of the available App Management API methods and properties, see the [App Management API Reference Documentation](https://docs.interop.io/browser/reference/javascript/app%20management/api/index.md).
