/

Module: Events

Configure the Events Module


Unchained supports the publish-subscribe (pub/sub) event model to keep track of events emitted in each module. By default it uses nodejs EventEmitter module to handle events but can easily extended to use any event tracker module by extending the EventAdapter class which we will briefly see later.

The unchained:core-events module exports three utility functions that can be used to interact with the registered event tracker, or register new custom events.

  • registerEvents: add's custom events that will be tracked. it takes array of event names.
  • emit(eventName, payload): used to emit events, either pre-built events or custom events registered using registerEvents. It take two arguments, name of the event we want to emit and an object of the data associated with the event.
  • subscribe(eventName: callBack): used for subscribing to events emitted by emit function. It takes two arguments, name of the event we want to subscribe to and a call back that will be takes one argument holding data for the associated event.

Note: to get list of pre-built or custom events registered on unchained use EventType resolver inside GraphQL playground.

Every event emitted from the engine is an object that has one property payload which is also an object that has different properties based on the event. We recommend you follow the same pattern when implementing custom events.

Built in Events

Bellow are events tracked under each module under the box:

core-assortments:

Event nameEmited when...payload
ASSORTMENT_CREATEAssortment is created{ assortment: {} }
ASSORTMENTADDFILTERAssortment filter is created{ assortmentFilter: {} }
ASSORTMENTADDLINKAssortment link is created{ parentAssortmentId: string, childAssortmentId: string }
ASSORTMENTADDPRODUCTProduct is added to an assortment{ assortmentProduct: {} }
ASSORTMENT_REMOVEAssortment is deleted{ assortmentId: string }
ASSORTMENTREMOVEFILTERAssortment filter is deleted{ assortmentFilterId: string }
ASSORTMENTREMOVELINKAssortment link is removed{ assortmentLinkId: string }
ASSORTMENTREORDERPRODUCTSAssortment product sort order is updated{ assortmentProducts: [] }
ASSORTMENTREORDERFILTERSAssortment filters sort order is updated{ assortmentFilters: [] }
ASSORTMENTREORDERLINKSAssortment link is updated{ assortmentLinks: [] }
ASSORTMENTSETBASEAssortment is set as base assortment{ assortmentId: string }
ASSORTMENT_UPDATEAssortment is updated{ assortmentId: string }
ASSORTMENTUPDATETEXTSAssortment text is updated{ assortmentId: string, assortmentTexts: [] }
ASSORTMENTADDMEDIAMedia is added for a product{ assortmentMedia: {} }
ASSORTMENTREMOVEMEDIAMedia is deleted from a product{ assortmentMediaId: string }
ASSORTMENTUPDATEMEDIA_TEXTProduct media text is updated{assortmentMedia: {}, mediaTexts: {} }

core-products

Event nameEmited when...payload
PRODUCTADDASSIGNMENTCONFIGURABLE_PRODUCT type is assigned proxy product{ productId: string, proxyId: string }
PRODUCTADDMEDIAMedia is added for a product{ productMedia: {} }
PRODUCTREVIEWADD_VOTEProduct review is recieves a vote{ productReview: {} }
PRODUCT_CREATEProduct is created{ product: {} }
PRODUCTCREATEBUNDLE_ITEMBUNDLE_PRODUCT is assigned bundle items{ productId: string }
PRODUCTREVIEWCREATEProduct review is created{ productReview : {} }
PRODUCTCREATEVARIATIONProduct variation is created{ productVariation: {} }
PRODUCTVARIATIONOPTION_CREATEProduct variation option is created{ productVariation: {} }
PRODUCTREMOVEBUNDLE_ITEMBundle item is removed from a BUNDLE_PRODUCT type{ productId: string, item: {} }
PRODUCT_REMOVEProduct is deleted{ productId: string }
PRODUCTREMOVEASSIGNMENTProxy assignment is removed from a CONFIGURABLE_PRODUCT type{ productId: string }
PRODUCTREMOVEMEDIAMedia is deleted from a product{ productMediaId: string }
PRODUCTREMOVEREVIEWProduct review is deleted{ productReviewId: string }
PRODUCTREMOVEREVIEW_VOTEProduct review vote is removed{ productReviewId: string, type: string, userId: string }
PRODUCTREMOVEVARIATIONProduct variation is removed from a product{ productVariationId: string }
PRODUCTREMOVEVARIATION_OPTIONProduct variation option is removed{ productVariationId: string, productVariationOptionValue: {} }
PRODUCTREORDERMEDIAProduct media sort order is updated{ productMedias: [] }
PRODUCT_UNPUBLISHProduct is unpublished{ product: {} }
PRODUCT_PUBLISHproduct is published{ product: {} }
PRODUCT_UPDATEproduct is updated{ productId: string, type: string, [commerce,support,warehousing]: {} }
PRODUCTUPDATEMEDIA_TEXTProduct media text is updated{productMedia: {}, mediaTexts: {} }
PRODUCTUPDATEREVIEWProduct review is updated{ productReview: {} }
PRODUCTUPDATETEXTSProduct text is updated{ product: {}, productTexts: [] }
PRODUCTUPDATEVARIATION_TEXTSproduct variation text is updated{ productVariation: {}, productVariationTexts: [] }

core-orders

Event nameEmitted when...payload
ORDERUPDATEDELIVERYOrder delivery information is updated{ orderDelivery: {} }
ORDERSIGNPAYMENTOrder payment provider is signed{ orderPayment: {}, transactionContext: {} }
ORDER_REMOVEOrder is deleted{ orderId: string }
ORDERADDPRODUCTProduct is added to an order{ orderPosition : {} }
ORDERADDDISCOUNTDiscount is added to an order{ discount: {} }
ORDER_CONFIRMEDOrder is confirmed{ order: {} }
ORDER_FULLFILLEDAll requested items are fullfiled for an order{ order: {} }
ORDERUPDATEPAYMENTOrder payment provider is updated{ orderPayment: {} }
ORDER_CREATENew Order is created{ order: {} }
ORDER_UPDATEOrder information is updated{ order: {}, field: string }
ORDERSETPAYMENT_PROVIDERPayment provider is assigned for an order{ order: {}, paymentProviderId: string }
ORDERSETDELIVERY_PROVIDERDelivery provider is assigned to an order{ order: {}, deliveryProviderId: string }
ORDEREMPTYCARTAll cart items are removed from an order{ orderId: string, count: number }
ORDERUPDATECART_ITEMItems in Order are updated, eg quantity{ orderPosition: {} }
ORDERREMOVECART_ITEMItems are delted from an order{ orderPosition: {} }
ORDERUPDATEDISCOUNTOrder discount is updated{ discount: {} }
ORDERREMOVEDISCOUNTDiscount associated with Order is removed{ discount: {} }
ORDER_CHECKOUTOrder is checked out successfuly{ order: {} }
ORDER_PAYOrder payment is complete{ orderPayment: {} }
ORDER_DELIVERYOrder delivery status is changed to deliverd{ orderDelivery: {} }

core-bookmarks

Event nameEmitted when...payload
BOOKMARK_CREATENew bookmark is created{ bookmarkId: string }
BOOKMARK_REMOVEBookmark is removed{ bookmarkId: string }

core-country

Event nameEmitted when...payload
COUNTRY_CREATENew country is created{ country: {} }
COUNTRY_UPDATECountry is update{ countryId: string }
COUNTRY_REMOVECountry is removed{ countryId: string }

core-currency

Event nameEmitted when...payload
CURRENCY_CREATENew currency is created{ currency: {} }
CURRENCY_UPDATECurrency is update{ currencyId: string }
CURRENCY_REMOVECurrency is removed{ currencyId: string }

core-language

Event nameEmitted when...payload
LANGUAGE_CREATENew language is created{ language: {} }
LANGUAGE_UPDATELanguage is update{ languageId: string }
LANGUAGE_REMOVELanguage is removed{ languageId: string }

core-filter

Event nameEmitted when...payload
FILTER_CREATENew filter is created{ filter: {} }
FILTER_UPDATEFilter is update{ filter: {} }
FILTER_REMOVEFilter is removed{ filterId: string }

core-payment

Event nameEmitted when...payload
PAYMENTPROVIDERCREATENew payment provider is created{ paymentProvider: {} }
PAYMENTPROVIDERUPDATEPayment provider is update{ paymentProvider: {} }
PAYMENTPROVIDERREMOVEPayment provider is removed{ paymentProvider: {} }

core-payment

Event nameEmitted when...payload
PAYMENTPROVIDERCREATENew payment provider is created{ paymentProvider: {} }
PAYMENTPROVIDERUPDATEPayment provider is update{ paymentProvider: {} }
PAYMENTPROVIDERREMOVEPayment provider is removed{ paymentProvider: {} }

core-warehousing

Event nameEmitted when...payload
WAREHOUSINGPROVIDERCREATENew warehousing provider is created{ warehousingProvider: {} }
WAREHOUSINGPROVIDERUPDATEWarehousing provider is update{ warehousingProvider: {} }
WAREHOUSINGPROVIDERREMOVEWarehousing provider is removed{ warehousingProvider: {} }

core-subscriptions

Event nameEmitted when...payload
SUBSCRIPTION_CREATENew subscription is created{ subscription: {} }

Tracking custom events

In addition to the built in event that come with unchained you can register your own custom event easily.

In order to do this, The custom events need to be registered at platform boot time using registerEvents helper function that takes array of event names to be tracked.

import { Meteor } from 'meteor/meteor';
import { registerEvents } from 'meteor/unchained:core-events';

Meteor.startup(() => {
  ...
  startPlatform({...});
  ...
  registerEvents([
      'CUSTOM_EVENT_ONE',
      'CUSTOM_EVENT_TWO',
      'CUSTOM_EVENT_THREE',
  ])
});

After initializing this at system start up, you can emit and subscribe in your code base.

import { registerEvents } from 'meteor/unchained:core-events';

subscribe('CUSTOM_EVENT_ONE', ({ payload }) => {
    console.log(payload.from);
});

emit('CUSTOM_EVENT_ONE', { from: "fcustom event one"});;

NOTE: before you can subscribe to an event, make sure it's registered first. Otherwise error will be thrown.

Setup custom event tracker

We can easily swap the default event tracker module (EventEmitter) used by unchained with out own module by implementing EventAdapter interface and registering it on EventDirector on system boot time. Both classes are exported from the core-events module.

import redis from 'redis';
import EventDirector, { EventAdapter } from 'meteor/unchained:core-events';

const { REDIS_PORT = 6379, REDIS_HOST = '127.0.0.1' } = process.env;

class RedisEventEmitter extends EventAdapter {
  redisPublisher = redis.createClient({
    port: REDIS_PORT,
    host: REDIS_HOST,
  });

  redisSubscriber = redis.createClient({
    port: REDIS_PORT,
    host: REDIS_HOST,
  });

  publish(eventName, payload) {
    this.redisPublisher.publish(eventName, JSON.stringify(payload));
  }

  subscribe(eventName, callBack) {
    this.redisSubscriber.on('message', (_channelName, payload) =>
      callBack(payload)
    );
      this.redisSubscriber.subscribe(eventName);
    }
  }
}

const handler = new RedisEventEmitter();

EventDirector.setEventAdapter(handler);

Meteor.startup(() => {
  ...
  startPlatform({...});
  ...
  registerEvents([
      'CUSTOM_EVENT_ONE',
      'CUSTOM_EVENT_TWO',
      'CUSTOM_EVENT_THREE',
  ])
});

Explanation:

We have decided to use redis for event tracking. In order to do that we have to create new class extending the EventAddapter interface and implement the two functions required subscribe & publish.

in this functions we defined how redis implements the pub/sub model.

Next all we need to is register it in EventDirector class using the static function setEventAdapter.

Edit on GitHub