# JavaScript

Source: https://docs.interop.io/desktop/capabilities/interception/javascript/index.html

## Overview

Available since io.Connect Desktop 9.6

The Interception API is accessible via the [`io.interception`](https://docs.interop.io/desktop/reference/javascript/interception/api/index.md) object.

## Registering Interception Handlers

For your app to be able to register interception handlers, you must [enable interception](https://docs.interop.io/desktop/capabilities/interception/overview/index.md#configuration) from the system configuration of **io.Connect Desktop**.

> ⚠️ *Note that only a single interception handler can be registered per operation within an API domain.*

To register an interception handler, use the [`register()`](https://docs.interop.io/desktop/reference/javascript/interception/api/index.md#API-register) method and provide an [`InterceptionRegistrationConfig`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionregistrationconfig/index.md) object as a required argument. Use this object to specify which io.Connect API [domains and operations](#domains__operations) within them to intercept, as well as to provide a handler function that will be invoked when the targeted operation has been intercepted.

The interception handler will receive an [`InterceptionMessage`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object as an argument, which you can use to extract data about the intercepted operation.

The `InterceptionMessage` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `callerId` | `string` | ID of the app that has invoked the platform operation. Can be used for tracking purposes. |
| `domain` | `string` | The io.Connect API domain in which the platform operation has been intercepted. |
| `operation` | `string` | The io.Connect platform operation that has been intercepted. |
| `operationArgs` | `any[]` | In the `"before"` phase, this property will contain the arguments with which the calling app has invoked the intercepted operation. In the `"after"` phase, this property will contain the result returned from executing the default platform implementation of the intercepted operation (or the result from the decorated operation, if the interception handler was invoked also in the `"before"` phase to modify the default operation). |
| `phase` | `"before"` \| `"after"` | Specifies whether the platform operation has been intercepted before or after the execution of its default implementation. |

The handler may return an [`InterceptionResponse`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object or `undefined` (for details on how the value returned from the interception handler affects the intercepted operation, see the [Interception Phases](#interception_phases) section).

The following example demonstrates how to register an interception handler for the `"raise"` operation of the Intents API domain (invoked by the [`raise()`](https://docs.interop.io/desktop/reference/javascript/intents/api/index.md#API-raise) method of the Intents API). The handler will be invoked during both interception phases - before and after the default platform implementation of the intercepted operation has been executed. In the `"before"` phase, the context data in the [`IntentRequest`](https://docs.interop.io/desktop/reference/javascript/intents/intentrequest/index.md) object with which the Intent was originally raised will be modified. In the `"after"` phase, the result in the [`IntentResult`](https://docs.interop.io/desktop/reference/javascript/intents/intentresult/index.md) object returned from executing the default platform operation will be modified:

```javascript
// Specify which API domains and which operations within them to intercept.
const interceptions = [
    {
        domain: "intents",
        operation: "raise"
        // If an interception phase isn't explicitly specified here, the handler
        // will be invoked during both interception phases - before and after the default
        // platform implementation of the intercepted operation has been executed.
    }
];

// Handler that will be invoked when the targeted platform operation has been intercepted.
// The handler will receive as an argument an `InterceptionMessage` object describing the intercepted operation.
const handler = (message) => {
    const phase = message.phase;

    // Defining the behavior of the handler based on the current interception phase.

    if (phase === "before") {
        // Extracting the `IntentRequest` object with which the Intent was originally raised.
        let raiseIntentArgs = message.operationArgs[0];

        // Modifying the context data with which to raise the Intent.
        raiseIntentArgs.context.data = { io: 42 };

        // The modified operation arguments must be returned as an `InterceptionResponse` object with an `operationArgs` property.
        const modifiedArgs = { operationArgs: [raiseIntentArgs] };

        // The execution of the default platform implementation will proceed with the modified arguments.
        return modifiedArgs;
    }

    if (phase === "after") {
        // Extracting the `IntentResult` object returned from executing
        // the default platform implementation for raising an Intent.
        let raiseIntentResult = message.operationArgs[0];

        // Modifying the `IntentResult` object.
        raiseIntentResult.context.data = { io: 42 };

        // The modified operation result must be returned as an `InterceptionResponse` object with an `operationResult` property.
        const modifiedResult = { operationResult: raiseIntentResult };

        return modifiedResult;
    }
};

// Configuration for registering an interception handler.
const config = { interceptions, handler };

// Registering an interception handler.
await io.interception.register(config);
```

## Unregistering Interception Handlers

You can register only a single interception handler per operation within an API domain. If you want to register another interception handler for the same operation within the same API domain, you must first unregister the already existing one.

To unregister an interception handler, use the [`unregister()`](https://docs.interop.io/desktop/reference/javascript/interception/api/index.md#API-unregister) method and provide an [`InterceptionUnregistrationConfig`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionunregistrationconfig/index.md) object as a required argument.

The following example demonstrates how to unregister an interception handler for the `"raise"` operation of the Intents API domain:

```javascript
const config = {
    interceptions: [
        {
            domain: "intents",
            operation: "raise"
        }
    ]
};

await io.interception.unregister(config);
```

## Interception Phases

The io.Connect API domain operations can be intercepted both before and after executing their default implementation. This enables you to have full control over the API domain operations: you can modify the operation arguments, prevent the execution of the default implementation, and modify the result returned from the default implementation.

Interception handlers can target a specific interception phase, or they can be invoked during both phases. To specify a phase during which to invoke the interception handler, use the `phase` property of the [`Interception`](https://docs.interop.io/desktop/reference/javascript/interception/interception/index.md) object when defining an API domain operation to intercept. The `phase` accepts `"before"`, `"after"`, or `"all"` (default) as a value.

The following example demonstrates how to register an interception handler that will only be invoked in the phase before the default platform implementation of the intercepted operation has been executed:

```javascript
const config = {
    interceptions: [
        {
            domain: "intents",
            operation: "raise",
            phase: "before"
        }
    ],
    handler: (message) => {
        console.log(`Interception phase: ${message.phase}`);
    }
};

await io.interception.register(config);
```

### Before Phase

The `"before"` phase allows you to modify the arguments for the intercepted operation, and to proceed with or prevent the execution of the default platform implementation of the operation.

#### Modifying the Operation Arguments

The interception handler has access to the operation arguments via the `operationArgs` array of the [`InterceptionMessage`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object that it receives as an argument. You can use this array to extract the operation arguments and modify them. You can modify and return from the interception handler directly the `InterceptionMessage` object, or you can return only the modified arguments in an [`InterceptionResponse`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object by using its `operationArgs` property.

> ⚠️ *Note that the `operationArgs` property of the `InterceptionResponse` object is taken into account only during the `"before"` phase.*

The following example demonstrates how to modify the argument (an [`IntentRequest`](https://docs.interop.io/desktop/reference/javascript/intents/intentrequest/index.md) object) for the `"raise"` operation of the Intents API domain in the `"before"` phase:

```javascript
const handler = (message) => {
    const phase = message.phase;

    if (phase === "before") {
        // Extracting the `IntentRequest` object with which the Intent was originally raised.
        let raiseIntentArgs = message.operationArgs[0];

        // Modifying the context data with which to raise the Intent.
        raiseIntentArgs.context.data = { io: 42 };

        // The modified operation arguments must be returned as an `InterceptionResponse` object with an `operationArgs` property.
        const modifiedArgs = { operationArgs: [raiseIntentArgs] };

        // The execution of the default platform implementation will proceed with the modified arguments.
        return modifiedArgs;
    }
};
```

#### Preventing the Execution of the Default Operation Implementation

To prevent the execution of the default implementation of the intercepted platform operation, use the `operationResult` property of the [`InterceptionResponse`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object to return an operation result directly from the interception handler in the `"before"` phase:

```javascript
const handler = (message) => {
    const phase = message.phase;

    if (phase === "before") {
        // The operation result must be returned as an `InterceptionResponse` object with an `operationResult` property.
        const result = { operationResult: { io: 42 } };

        // Returning a result will prevent the execution of
        // the default implementation of the intercepted operation.
        return result;
    }
};
```

#### Proceeding with the Default Operation Implementation

To instruct the platform to proceed with the default implementation of the intercepted operation, return `undefined` from the interception handler in the `"before"` phase:

```javascript
const handler = (message) => {
    const phase = message.phase;

    if (phase === "before") {
        // This will instruct the platform to proceed with
        // the default implementation of the intercepted operation.
        return;
    }
};
```

### After Phase

The `"after"` phase allows you to modify the result returned from executing the default platform implementation of the intercepted operation, or the result from the decorated operation, if the interception handler was invoked also in the `"before"` phase to modify the default operation. You can also choose to return directly the already calculated result without modifying it.

#### Modifying the Operation Result

The interception handler has access to the already calculated result via the `operationArgs` array of the [`InterceptionMessage`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object that it receives as an argument. You can use this array to extract the operation result and modify it. You must return the modified result in an [`InterceptionResponse`](https://docs.interop.io/desktop/reference/javascript/interception/interceptionresponse/index.md) object by using its `operationResult` property.

The following example demonstrates how to modify the result (an [`IntentResult`](https://docs.interop.io/desktop/reference/javascript/intents/intentresult/index.md) object) from the `"raise"` operation of the Intents API domain in the `"after"` phase:

```javascript
const handler = (message) => {
    const phase = message.phase;

    if (phase === "after") {
        // Extracting the `IntentResult` object returned from executing
        // the default platform implementation for raising an Intent.
        let raiseIntentResult = message.operationArgs[0];

        // Modifying the `IntentResult` object.
        raiseIntentResult.context.data = { io: 42 };

        // The modified operation result must be returned as an `InterceptionResponse` object with an `operationResult` property.
        const modifiedResult = { operationResult: raiseIntentResult };

        return modifiedResult;
    }
};
```

#### Returning the Already Calculated Result

To return the already calculated result for the intercepted operation without modifying it, return `undefined` from the interception handler in the `"after"` phase:

```javascript
const handler = (message) => {
    const phase = message.phase;

    if (phase === "after") {
        // This will instruct the platform to return
        // the already calculated result for the intercepted operation.
        return;
    }
};
```

## Domains & Operations

This section describes the io.Connect API domain and operation IDs, and the shape of the operation arguments and results each operation expects in order to be executed.

> ⚠️ *Note that, currently, it's possible to intercept control message only for the Intents API domain.*

### Intents

To send a control message to the [Intents](https://docs.interop.io/desktop/capabilities/data-sharing/intents/overview/index.md) domain, set the `domain` property of the [`Interception`](https://docs.interop.io/desktop/reference/javascript/interception/interception/index.md) object to `"intents"`.

The following io.Connect operations are available for this domain:

#### "filterHandlers"

Available since io.Connect Desktop 10.0

Filters Intent handlers by specified criteria.

The argument for this operation is a [`HandlerFilter`](https://docs.interop.io/desktop/reference/javascript/intents/handlerfilter/index.md) object.

Returns a [`FilterHandlersResult`](https://docs.interop.io/desktop/reference/javascript/intents/filterhandlersresult/index.md) object.

#### "raise"

Raises an Intent.

The argument for this operation is an [`IntentRequest`](https://docs.interop.io/desktop/reference/javascript/intents/intentrequest/index.md) object.

Returns an [`IntentResult`](https://docs.interop.io/desktop/reference/javascript/intents/intentresult/index.md) object.

## API Reference

For a complete list of the available Interception API methods and properties, see the [Interception API reference documentation](https://docs.interop.io/desktop/reference/javascript/interception/api/index.md).
