# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.guardianservice.app/technical-information/users/standard-registry-users-schemas-and-policies/policies/external-events.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
