export const metadata = {
  title: `How to Create an Event Module`,
}

# {metadata.title}

In this guide, you’ll learn how to create an Event Module.

## 1. Create Module Directory

Start by creating a new directory for your module. For example, `src/modules/my-event`.

---

## 2. Create the Event Service

Create the file `src/modules/my-event/service.ts` that holds the implementation of the event service.

The Event Module's main service must extend the `AbstractEventBusModuleService` class imported from `@medusajs/utils`:

```ts title="src/modules/my-event/service.ts"
import { EmitData, Message } from "@medusajs/types"
import { AbstractEventBusModuleService } from "@medusajs/utils"

class MyEventService extends AbstractEventBusModuleService {
  emit<T>(eventName: string, data: T, options: Record<string, unknown>): Promise<void>;
  emit<T>(data: EmitData<T>[]): Promise<void>;
  emit<T>(data: Message<T>[]): Promise<void>;
  emit(eventName: unknown, data?: unknown, options?: unknown): Promise<void> {
    throw new Error("Method not implemented.")
  }
}

export default MyEventService
```

The service implements the required methods based on the desired publish/subscribe logic.

### Note About the eventToSubscribersMap Property

The `AbstractEventBusModuleService` has a field `eventToSubscribersMap`, which is a JavaScript Map. The map's keys are the event names, whereas the value of each key is an array of subscribed handler functions.

In your custom implementation, you can use this property to manage the subscribed handler functions:

```ts
const eventSubscribers = 
  this.eventToSubscribersMap.get(eventName) || []
```

### Implement emit Method

The `emit` method is used to push an event from the Medusa application into your messaging system. The subscribers to that event would then pick up the message and execute their asynchronous tasks.

The `emit` method has three different signatures:

1. The first signature accepts three parameters:
    - The first parameter is a string indicating the name of the event to trigger.
    - The second parameter is data to send to subscribers of that event.
    - The third optional parameter can be used to pass options specific to the event service.
2. The second signature accepts one parameter, which is an array of objects having the following properties:
    - `eventName`: A string indicating the name of the event to trigger.
    - `data`: The data to send to subsribers of that event.
    - `options`: (optional) options specific to the event service.
3. The third signature accepts one parameter, which is an array of objects having the following properties:
    - `eventName`: A string indicating the name of the event to trigger.
    - `body`: An object of event-related data. It has two properties: `data` holding the data of the event, and `metadata` which is an object with more details on how the event was emitted, such as the action that occurred or the service that emitted it.
    - `options`: (optional) options specific to the event service.

You can implement your method in a way that supports both signatures by checking the type of the first input. For example:

```ts title="src/modules/my-event/service.ts"
class MyEventService extends AbstractEventBusModuleService {
  // ...
  emit<T>(eventName: string, data: T, options: Record<string, unknown>): Promise<void>;
  emit<T>(data: EmitData<T>[]): Promise<void>;
  emit<T>(data: Message<T>[]): Promise<void>;
  emit(eventOrData: unknown, data?: unknown, options?: unknown): Promise<void> {
    const isBulkEmit = Array.isArray(eventOrData)

    // ...
  }
}
```

---

## 3. Create Module Definition File

Create the file `src/modules/my-event/index.ts` with the following content:

```ts
import MyEventService from "./service"

export default {
  service: MyEventService,
}
```

This exports the module's definition, indicating that the `MyEventService` is the main service of the module.

---

## 4. Use Module

To use your Event Module, add it to the `modules` object exported as part of the configurations in `medusa-config.js`. An Event Module is added under the `eventBus` key.

For example:

```js title="medusa-config.js"
const modules = {
  // other modules...
  eventBus: {
    resolve: "./dist/modules/my-event/index.ts",
    options: {
      // any necessary options
    },
  },
}
```
