Concepts
Modules
Modules are how SDK capabilities are expanded, while still keeping the core lightweight and flexible.
This extensibility allows for integrating with third-party analytics/logging services, or your own custom backend ones with ease.
Integration use cases#
Modules can be used to support few different use cases:
- Transports: for sending events to various destinations
- Lookups: for reading information on demand in conditions and transforms
- Handlers: for executing custom code via effects
- Persistence: for persisting data across sessions in attributes and effects
Creating a module#
A module is a simple JavaScript object that has a few properties:
name: unique identifier for the module (required)
and all these optional methods:
lookup: function that returns a value for a given keytransport: function that sends an event to a destinationhandle: function that executes custom logicreadFromStorage: function that reads a value from a storage layerwriteToStorage: function that writes a value to a storage layerremoveFromStorage: function that removes a value from a storage layersetup: initialize subscriptions or resourcesflush: attempt queued workclose: release subscriptions, handlers, timers, and memory
If we are sticking to JavaScript SDK, we can define a module like this:
export function createCustomModule() { return { name: "custom", /** * Lookup: used in conditions and transforms */ lookup: async ({ key }) => { return "some value"; }, /** * Transport: used in destinations */ transport: async ({ payload, eventName, eventLevel, error, destinationName, }) => { // send the payload somewhere here... // if tracked event is an error, then `error` will be the error object }, /** * Handle: used in effects */ handle: async ({ effectName, effect, step }) => { const { params } = step; console.log("Custom handler called for effect:", effectName); }, /** * Persistence: used in attributes and effects */ readFromStorage: async ({ key }) => { return "some value"; }, writeToStorage: async ({ key, value }) => { // write value to the storage layer here... }, removeFromStorage: async ({ key }) => { // remove value from the storage layer here... }, };}You are advised to have a function that returns the module object, so that it enables others to customize the module further as needed.
TypeScript usage#
You can make use of the EventvisorModule type for type safety:
import type { EventvisorModule } from "@eventvisor/sdk";export function createCustomModule(): EventvisorModule { return { name: "custom", // ... };}setup(api) receives revision and diagnostic helpers. Effect handlers also receive api.track(). Use that method for nested tracking so Eventvisor can detect effect cycles.
Queueing modules should implement flush(). await eventvisor.flush() runs every module flush in parallel, and close() flushes before closing modules.
Module setup#
Now we can register this module when initializing the SDK:
import { createEventvisor } from "@eventvisor/sdk";import { createCustomModule } from "./custom";const eventvisor = createEventvisor({ modules: [ createCustomModule(), ],});Usage examples#
Lookup#
Lookups can be performed in conditions and transforms:
conditions: - lookup: custom.myKey operator: equals value: myValueTransport#
Transports can be used in destinations:
# ...transport: customHandler#
Handlers can be used in effects:
# ...steps: - handler: custom params: key: valuePersist#
Storage modules can be used to persist data across sessions:
# ...persist: customLearn more in persistence page.

