> For the complete documentation index, see [llms.txt](https://docs.guardianservice.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.guardianservice.app/technical-information/users/standard-registry-users-schemas-and-policies/policies/external-events.md).

# External Events

### Introduction

Guardian will publish a number of events to the NATS server to hook into those events, which extends the function that is suitable to the solution.

### Hooks to an external event

To hook into Guardian events, we need to have a client, that is connected to the same NATS instance with Guardian and implement the response function for a specific event.

Below is the sample for .NodeJs and in the case of other languages please refer to [Nats.io](https://nats.io/) for complete documentation.

#### publish/subscribe to events

The events with type=`publish` is publish/subscribe pattern so that the same message can be received by multiple clients. If there are multiple clients make sure it is handled by duplicate message processing.

```js
import { connect, JSONCodec } from "nats";

(async () => {
  const nc = await connect({ servers: "localhost:4222" });

  const c = JSONCodec();
  const sub = nc.subscribe("externals-events.ipfs_added_file");

  (async () => {
    for await (const m of sub) {
      console.log(`[${sub.getProcessed()}]`, c.decode(m.data));
    }
    console.log("subscription closed");
  })();
})();
```

To get more information please click <https://github.com/nats-io/nats.js#publish-and-subscribe>

#### request/reply events

Some event has a type=`request` for which we need to subscribe and respond to the event.

#### Example:

For the before/after IPFS event, if the listener responds with an error then the IPFS service will be skipped and upload/respond to the actual content. This same scenario also happens when we do not have a listener to an event. For example, we can use this to encrypt/decrypt IPFS content file

```js
const responseToIpfsEvent = (type: string, cb: (data: Buffer) => Buffer) => {
        const sub = nc.subscribe(type);
        console.log("√ Listening to IPFS event: %s", type);
        (async () => {
            for await (const m of sub) {
                console.log(`[${sub.getProcessed()} - ${m.subject}]`);
                try {
                    const payload = c.decode(m.data) as any;
                    const body = cb(Buffer.from(payload.content, 'base64'));
                    const responseMessage = { body: body.toString('base64') }
                    const archResponse = zlib.deflateSync(JSON.stringify(responseMessage)).toString('binary');
                    m.respond(StringCodec().encode(archResponse));
                } catch (e) {
                    // It is important that you should handle the content to make sure that is your encrypted/decrypted, skip if that is system ipds file
                    const archResponse = zlib.deflateSync(JSON.stringify({ error: e.message })).toString('binary');
                    m.respond(StringCodec().encode(archResponse));
                }

            }
            console.log("Subscription closed");
        })();
    };
```

### External events list

| event                                         | type         | payload                        |                                           notes                                          | Example                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------------------------------------- | ------------ | ------------------------------ | :--------------------------------------------------------------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| external-events.token\_minted                 | publish      | { tokenId, tokenValue, memo }  |                      Triggered when a token is successfully minted.                      | <p>{<br>tokenId: '0.0.1554488',<br>tokenValue: 10<br>}</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| external-events.token\_mint\_complete         | publish      | { tokenValue }                 |                        Triggered when all tokens have been minted.                       | <p>{<br>tokenValue: 10<br>}</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| external-events.error\_logs                   | publish      | { message, type, attributes }  |                  Triggered when an error is sent to the logger service.                  | <p>{<br>id: '9b9d1cd0-cff4-467b-a3bc-8866fa1cfd18',<br>error: 'failed store/add invocation'<br>}</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| external-events.block\_event                  | publish      | \<blockEventData>              |                            Represents a block external event.                            | <p>\[<br>{<br>type: 'Set',<br>blockUUID: '37c1b465-5261-4626-8972-f367301974a1',<br>blockType: 'requestVcDocumentBlock',<br>blockTag: 'bad\_token\_form',<br>userId: 'did:hedera:testnet:FF7nFWaMCkHjEfJLtcUQTLRQao9yCCj6mc4MRvgDjStW\_0.0.5277702',<br>data: { documents: \[Array] }<br>}<br>]</p>                                                                                                                                                                                                                                                                                                |
| external-events.ipfs\_added\_file             | publish      | { cid, url }                   |                          Triggered when a file is added to IPFS.                         | <p>{ cid: 'QmPs2ufs5VQPYGGX1ewEjKSR8zuEmeuWK4GBKFHZjXTCAQ',</p><p>url: '<a href="ipfs://QmPs2ufs5VQPYGGX1ewEjKSR8zuEmeuWK4GBKFHZjXTCAQ">ipfs\://QmPs2ufs5VQPYGGX1ewEjKSR8zuEmeuWK4GBKFHZjXTCAQ</a>' }</p>                                                                                                                                                                                                                                                                                                                                                                                          |
| external-events.ipfs\_before\_upload\_content | request      | {content}                      |  The base64-encoded content (buffer) to be hooked and modified before uploading to IPFS. | <p>{<br>content: 'eyJAY29udGV4dCI6eyJAdmVyc2lvbiI6MS4xLCJAdm9jYWIiOiJodHRwczovL3czaWQub3JnL3RyYWNlYWJpbGl0eS8jdW5kZWZpbmVkVGVybSIsImlkIjoiQGlkIiwidHlwZSI6IkB0eXBlIiwiYTkwYWU1OWEtNjhhMS00YmY3LWFmNDgtNTRhNzhiNWQwYzI5JjEiOnsiQGlkIjoic2NoZW1hOmE5MGFlNTlhLTY4YTEtNGJmNy1hZjQ4LTU0YTc4YjVkMGMyOSNhOTBhZTU5YS02OGExLTRiZjctYWY0OC01NGE3OGI1ZDBjMjkmMSIsIkBjb250ZXh0Ijp7InBvbGljeUlkIjp7IkB0eXBlIjoiaHR0cHM6Ly93d3cuc2NoZW1hLm9yZy90ZXh0In0sInJlZiI6eyJAdHlwZSI6Imh0dHBzOi8vd3d3LnNjaGVtYS5vcmcvdGV4dCJ9fX19fQ=='<br>}</p>                                                                           |
| external-events.ipfs\_after\_read\_content    | request      | {content}                      | The base64-encoded content (buffer) to be modified or processed after reading from IPFS. | QmPs2ufs5VQPYGGX1ewEjKSR8zuEmeuWK4GBKFHZjXTCAQ                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| external-events.ipfs\_loaded\_file            | subscription | { taskId, fileContent, error } |                      Receives an event when a file load is complete.                     | <p>{<br>taskId: 'be1c8bc2-c100-47c5-af48-46c10b5fde55',<br>fileContent: 'eyJAY29udGV4dCI6eyJAdmVyc2lvbiI6MS4xLCJAdm9jYWIiOiJodHRwczovL3czaWQub3JnL3RyYWNlYWJpbGl0eS8jdW5kZWZpbmVkVGVybSIsImlkIjoiQGlkIiwidHlwZSI6IkB0eXBlIiwiYTkwYWU1OWEtNjhhMS00YmY3LWFmNDgtNTRhNzhiNWQwYzI5JjEiOnsiQGlkIjoic2NoZW1hOmE5MGFlNTlhLTY4YTEtNGJmNy1hZjQ4LTU0YTc4YjVkMGMyOSNhOTBhZTU5YS02OGExLTRiZjctYWY0OC01NGE3OGI1ZDBjMjkmMSIsIkBjb250ZXh0Ijp7InBvbGljeUlkIjp7IkB0eXBlIjoiaHR0cHM6Ly93d3cuc2NoZW1hLm9yZy90ZXh0In0sInJlZiI6eyJAdHlwZSI6Imh0dHBzOi8vd3d3LnNjaGVtYS5vcmcvdGV4dCJ9fX19fQ',<br>error: undefined<br>}</p> |

### Example

This example demonstrates the implementation of encryption/decryption of simple IPFS content.

Please refer to <https://github.com/hashgraph/guardian/blob/main/common/src/mq/sample-external-client.ts>
