@liquidcommercedev/rmn-sdk 1.4.6-beta.4 → 1.4.6-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -54,6 +54,9 @@ var RMN_FILTER_PROPERTIES;
54
54
  })(RMN_FILTER_PROPERTIES || (RMN_FILTER_PROPERTIES = {}));
55
55
  var RMN_SPOT_EVENT;
56
56
  (function (RMN_SPOT_EVENT) {
57
+ RMN_SPOT_EVENT["MOUNTED"] = "MOUNTED";
58
+ RMN_SPOT_EVENT["UNMOUNTED"] = "UNMOUNTED";
59
+ RMN_SPOT_EVENT["RESIZED"] = "RESIZED";
57
60
  RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
58
61
  RMN_SPOT_EVENT["CLICK"] = "CLICK";
59
62
  RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
@@ -15162,6 +15165,46 @@ const GFONT_CORMORANT = `
15162
15165
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
15163
15166
  `;
15164
15167
 
15168
+ class IntersectionObserverService {
15169
+ constructor(defaultOptions = {}) {
15170
+ this.observers = new Map();
15171
+ this.defaultOptions = {
15172
+ root: null,
15173
+ rootMargin: '0px',
15174
+ threshold: 0.5,
15175
+ ...defaultOptions,
15176
+ };
15177
+ }
15178
+ observe(element, callback, options = {}) {
15179
+ const mergedOptions = { ...this.defaultOptions, ...options };
15180
+ const ioCallback = (entries) => {
15181
+ entries.forEach((entry) => {
15182
+ if (entry.isIntersecting) {
15183
+ callback(entry);
15184
+ }
15185
+ });
15186
+ };
15187
+ const observer = new IntersectionObserver(ioCallback, mergedOptions);
15188
+ this.observers.set(element, observer);
15189
+ observer.observe(element);
15190
+ }
15191
+ unobserve(element) {
15192
+ const observer = this.observers.get(element);
15193
+ if (observer) {
15194
+ observer.unobserve(element);
15195
+ observer.disconnect();
15196
+ this.observers.delete(element);
15197
+ }
15198
+ }
15199
+ unobserveAll() {
15200
+ this.observers.forEach((observer, element) => {
15201
+ observer.unobserve(element);
15202
+ observer.disconnect();
15203
+ });
15204
+ this.observers.clear();
15205
+ }
15206
+ }
15207
+
15165
15208
  class ResizeObserverService {
15166
15209
  constructor({ element, maxSize, minScale }) {
15167
15210
  this.element = element;
@@ -15467,8 +15510,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15467
15510
  this.addEventListener('spotSizeChanged', this.handleCarouselSizeChanged.bind(this));
15468
15511
  }
15469
15512
  }
15470
- handleCarouselSizeChanged(event) {
15471
- console.info('Carousel Size Changed', event);
15513
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
15514
+ handleCarouselSizeChanged(_event) {
15515
+ // console.info('Carousel Size Changed', event);
15472
15516
  }
15473
15517
  render() {
15474
15518
  var _a;
@@ -15694,7 +15738,7 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15694
15738
  * #########################################################
15695
15739
  */
15696
15740
  handleSpotSizeChanged(event) {
15697
- console.info('Spot Size Changed', event);
15741
+ // console.info('Spot Size Changed', event);
15698
15742
  // Adjust text elements font size based on the scale factor
15699
15743
  this.adjustFontSize(event.detail.scale);
15700
15744
  }
@@ -15706,8 +15750,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15706
15750
  elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
15707
15751
  if (element instanceof HTMLElement) {
15708
15752
  if (!this.originalFontSizes.has(element)) {
15709
- const orignalSize = parseFloat(window.getComputedStyle(element).fontSize);
15710
- this.originalFontSizes.set(element, orignalSize);
15753
+ const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
15754
+ this.originalFontSizes.set(element, originalSize);
15711
15755
  }
15712
15756
  const originalSize = this.originalFontSizes.get(element);
15713
15757
  const newFontSize = originalSize * scaleFactor;
@@ -17538,11 +17582,12 @@ function rbSmallDiscoverToutTemplate(spot, config) {
17538
17582
  }
17539
17583
 
17540
17584
  /**
17541
- * Creates the spot html string based on the provided spot data.
17585
+ * Returns the HTML element for the given spot.
17542
17586
  *
17543
- * @param {ISpot} spot - The spot data.
17587
+ * @param {ISpot} spot - The spot object.
17588
+ * @param {ISpotTemplateConfig} config - The spot template configuration.
17544
17589
  *
17545
- * @return {string} - The spot html string.
17590
+ * @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
17546
17591
  */
17547
17592
  const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
17548
17593
  const templates = {
@@ -17615,6 +17660,228 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
17615
17660
  return spotHtmlStringToElement(spotHtmlString);
17616
17661
  };
17617
17662
 
17663
+ /**
17664
+ * PubSub class
17665
+ * Manages event subscriptions and publications
17666
+ * @template IEventMap A record type defining the structure of events and their data
17667
+ */
17668
+ class PubSub {
17669
+ constructor() {
17670
+ /**
17671
+ * Object to store subscribers for each event type
17672
+ */
17673
+ this.subscribers = {};
17674
+ }
17675
+ /**
17676
+ * Subscribe to an event
17677
+ * @param eventType - The type of event to subscribe to
17678
+ * @param callback - The function to be called when the event is published
17679
+ * @returns A function to unsubscribe from the event
17680
+ *
17681
+ * @Example:
17682
+ * const unsubscribe = pubSub.subscribe('userLogin', (data) => {
17683
+ * console.log(`User ${data.username} logged in`);
17684
+ * });
17685
+ */
17686
+ subscribe(eventType, callback) {
17687
+ if (!this.subscribers[eventType]) {
17688
+ this.subscribers[eventType] = [];
17689
+ }
17690
+ this.subscribers[eventType].push(callback);
17691
+ // Return an unsubscribe function
17692
+ return () => {
17693
+ this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
17694
+ };
17695
+ }
17696
+ /**
17697
+ * Publish an event
17698
+ * @param eventType - The type of event to publish
17699
+ * @param data - The data to be passed to the event subscribers
17700
+ *
17701
+ * @Example:
17702
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
17703
+ */
17704
+ publish(eventType, data) {
17705
+ if (!this.subscribers[eventType]) {
17706
+ return;
17707
+ }
17708
+ this.subscribers[eventType].forEach((callback) => callback(data));
17709
+ }
17710
+ }
17711
+ /**
17712
+ * Usage Example:
17713
+ *
17714
+ * interface IEventMap {
17715
+ * userLogin: { username: string; timestamp: number };
17716
+ * pageView: { url: string; timestamp: number };
17717
+ * }
17718
+ *
17719
+ * const pubSub = new PubSub<IEventMap>();
17720
+ *
17721
+ * // Subscribe to events
17722
+ * const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
17723
+ * console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
17724
+ * });
17725
+ *
17726
+ * pubSub.subscribe('pageView', (data) => {
17727
+ * console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
17728
+ * });
17729
+ *
17730
+ * // Publish events
17731
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
17732
+ * pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
17733
+ *
17734
+ * // Unsubscribe from an event
17735
+ * unsubscribeLogin();
17736
+ */
17737
+
17738
+ class EventService {
17739
+ constructor() {
17740
+ this.pubSub = new PubSub();
17741
+ this.activeSpots = new Map();
17742
+ this.intersectionObserver = new IntersectionObserverService();
17743
+ }
17744
+ static getInstance() {
17745
+ if (!EventService.instance) {
17746
+ EventService.instance = new EventService();
17747
+ }
17748
+ return EventService.instance;
17749
+ }
17750
+ registerSpot({ placementId, element, spot }) {
17751
+ this.activeSpots.set(spot.id, {
17752
+ placementId,
17753
+ element,
17754
+ impressionTracked: false,
17755
+ });
17756
+ // Handle resize observer
17757
+ // this.handleResizeObserver(placementId, spot, element);
17758
+ // Handle intersection observer
17759
+ this.handleIntersectionObserver(placementId, spot, element);
17760
+ // Attach click event listener
17761
+ element.addEventListener('click', async () => {
17762
+ var _a, _b;
17763
+ this.pubSub.publish(RMN_SPOT_EVENT.CLICK, {
17764
+ placementId,
17765
+ spotId: spot.id,
17766
+ element,
17767
+ });
17768
+ // Fire click event
17769
+ await this.fireEvent({
17770
+ event: RMN_SPOT_EVENT.CLICK,
17771
+ eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
17772
+ });
17773
+ });
17774
+ // Publish spot created event
17775
+ this.pubSub.publish(RMN_SPOT_EVENT.MOUNTED, {
17776
+ placementId,
17777
+ spotId: spot.id,
17778
+ spotType: spot.spot,
17779
+ spotVariant: spot.variant,
17780
+ element,
17781
+ });
17782
+ }
17783
+ unregisterSpot(spotId) {
17784
+ const spotData = this.activeSpots.get(spotId);
17785
+ if (spotData) {
17786
+ this.intersectionObserver.unobserve(spotData.element);
17787
+ // this.resizeObserver?.disconnect();
17788
+ this.pubSub.publish(RMN_SPOT_EVENT.UNMOUNTED, {
17789
+ placementId: spotData.placementId,
17790
+ spotId,
17791
+ });
17792
+ this.activeSpots.delete(spotId);
17793
+ }
17794
+ }
17795
+ // private handleResizeObserver(placementId: string, spot: ISpot, element: HTMLElement): void {
17796
+ // // this.resizeObserver = new ResizeObserverService({
17797
+ // // element,
17798
+ // // maxSize: {
17799
+ // // width: spot.width,
17800
+ // // height: spot.height,
17801
+ // // },
17802
+ // // minScale: 0.25,
17803
+ // // });
17804
+ //
17805
+ // const sizeChangedCb = (event: ISizeChangedEvent) => {
17806
+ // // Publish spot resized event
17807
+ // this.pubSub.publish(RMN_SPOT_EVENT.RESIZED, {
17808
+ // placementId,
17809
+ // spotId: spot.id,
17810
+ // scale: event.detail.scale,
17811
+ // previousDimensions: {
17812
+ // width: event.detail.width,
17813
+ // height: event.detail.height,
17814
+ // },
17815
+ // currentDimensions: {
17816
+ // width: event.detail.newWidth,
17817
+ // height: event.detail.newHeight,
17818
+ // },
17819
+ // });
17820
+ // };
17821
+ //
17822
+ // element.addEventListener('spotSizeChanged', sizeChangedCb as EventListener);
17823
+ // }
17824
+ handleIntersectionObserver(placementId, spot, element) {
17825
+ const spotIsVisibleCb = async () => {
17826
+ var _a, _b;
17827
+ this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
17828
+ placementId,
17829
+ spotId: spot.id,
17830
+ element,
17831
+ });
17832
+ this.intersectionObserver.unobserve(element);
17833
+ this.activeSpots.set(spot.id, {
17834
+ placementId,
17835
+ element,
17836
+ impressionTracked: true,
17837
+ });
17838
+ // Fire impression event
17839
+ await this.fireEvent({
17840
+ event: RMN_SPOT_EVENT.IMPRESSION,
17841
+ eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
17842
+ });
17843
+ };
17844
+ this.intersectionObserver.observe(element, spotIsVisibleCb);
17845
+ }
17846
+ subscribe(eventType, callback) {
17847
+ return this.pubSub.subscribe(eventType, callback);
17848
+ }
17849
+ publish(eventType, data) {
17850
+ this.pubSub.publish(eventType, data);
17851
+ }
17852
+ /**
17853
+ * Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
17854
+ *
17855
+ * @param {IFireEventParams} params - The parameters for firing the event.
17856
+ * @param {RMN_SPOT_EVENT} params.event - The event type.
17857
+ * @param {string} params.eventUrl - The URL to which the event is sent.
17858
+ * @returns {Promise<void>} - A promise that resolves when the event is fired.
17859
+ */
17860
+ async fireEvent({ event, eventUrl }) {
17861
+ const didFireEvent = navigator.sendBeacon(eventUrl);
17862
+ if (didFireEvent && event === RMN_SPOT_EVENT.CLICK) {
17863
+ window.location.href = this.getRedirectUrlFromPayload(eventUrl);
17864
+ }
17865
+ }
17866
+ /**
17867
+ * Extracts and decodes a URL from a base64-encoded query parameter.
17868
+ *
17869
+ * @param {string} url - The URL containing the base64-encoded query parameter.
17870
+ * @returns {string} - The decoded URL or an empty string if decoding fails.
17871
+ */
17872
+ getRedirectUrlFromPayload(url) {
17873
+ var _a, _b;
17874
+ const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
17875
+ try {
17876
+ const data = JSON.parse(atob(base64String));
17877
+ return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
17878
+ }
17879
+ catch (_c) {
17880
+ return '';
17881
+ }
17882
+ }
17883
+ }
17884
+
17618
17885
  const SELECTION_API_PATH = '/spots/selection';
17619
17886
 
17620
17887
  class SelectionService extends BaseApi {
@@ -17649,6 +17916,7 @@ class LiquidCommerceRmnClient {
17649
17916
  constructor(auth) {
17650
17917
  this.selectionService = SelectionService.getInstance(auth);
17651
17918
  this.elementService = ElementService.getInstance();
17919
+ this.eventService = EventService.getInstance();
17652
17920
  }
17653
17921
  /**
17654
17922
  * Makes a selection request on our server based on the provided data.
@@ -17699,6 +17967,14 @@ class LiquidCommerceRmnClient {
17699
17967
  }
17700
17968
  }
17701
17969
  }
17970
+ /**
17971
+ * Returns the event manager instance.
17972
+ *
17973
+ * @return {EventService} - The event manager instance.
17974
+ */
17975
+ eventManager() {
17976
+ return this.eventService;
17977
+ }
17702
17978
  /**
17703
17979
  * Makes a selection request on our server based on the provided data.
17704
17980
  *
@@ -17739,6 +18015,11 @@ class LiquidCommerceRmnClient {
17739
18015
  console.warn(`RmnSdk: Failed to inject carousel spot element. Could not create element for type "${spot.spot}".`);
17740
18016
  return;
17741
18017
  }
18018
+ this.eventSpotElement({
18019
+ spot,
18020
+ placementId: placement.id,
18021
+ element: content,
18022
+ });
17742
18023
  carouselSlides.push(content);
17743
18024
  }
17744
18025
  const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
@@ -17790,8 +18071,20 @@ class LiquidCommerceRmnClient {
17790
18071
  console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
17791
18072
  return;
17792
18073
  }
18074
+ this.eventSpotElement({
18075
+ spot,
18076
+ placementId: injectItem.placementId,
18077
+ element: spotElement,
18078
+ });
17793
18079
  placement.replaceChildren(spotElement);
17794
18080
  }
18081
+ eventSpotElement({ spot, placementId, element, }) {
18082
+ this.eventService.registerSpot({
18083
+ placementId,
18084
+ element,
18085
+ spot,
18086
+ });
18087
+ }
17795
18088
  /**
17796
18089
  * Prevents duplicate placement ids in the inject data.
17797
18090
  *
@@ -49,6 +49,9 @@ export declare enum RMN_FILTER_PROPERTIES {
49
49
  SECTION = "section"
50
50
  }
51
51
  export declare enum RMN_SPOT_EVENT {
52
+ MOUNTED = "MOUNTED",
53
+ UNMOUNTED = "UNMOUNTED",
54
+ RESIZED = "RESIZED",
52
55
  IMPRESSION = "IMPRESSION",
53
56
  CLICK = "CLICK",
54
57
  PURCHASE = "PURCHASE",
@@ -1,12 +1,12 @@
1
1
  import type { ICreateElementConfig } from 'modules/element';
2
- export type CarouselNavPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'middle-left' | 'middle-right' | 'middle-sides';
2
+ export type CarouselNavPositionType = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'middle-left' | 'middle-right' | 'middle-sides';
3
3
  export interface ICarouselDotOptions {
4
- position: CarouselNavPosition;
4
+ position: CarouselNavPositionType;
5
5
  color: string;
6
6
  activeColor: string;
7
7
  }
8
8
  export interface ICarouselButtonOptions {
9
- position: CarouselNavPosition;
9
+ position: CarouselNavPositionType;
10
10
  together: boolean;
11
11
  textColor: string;
12
12
  backgroundColor: string;
@@ -1,10 +1,11 @@
1
1
  import type { ISpot } from 'types';
2
2
  import type { ISpotTemplateConfig } from './template.type';
3
3
  /**
4
- * Creates the spot html string based on the provided spot data.
4
+ * Returns the HTML element for the given spot.
5
5
  *
6
- * @param {ISpot} spot - The spot data.
6
+ * @param {ISpot} spot - The spot object.
7
+ * @param {ISpotTemplateConfig} config - The spot template configuration.
7
8
  *
8
- * @return {string} - The spot html string.
9
+ * @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
9
10
  */
10
11
  export declare const SPOT_TEMPLATE_HTML_ELEMENT: (spot: ISpot, config?: ISpotTemplateConfig) => HTMLElement | null;
@@ -1,5 +1,72 @@
1
1
  import type { RMN_SPOT_EVENT } from 'enums';
2
+ import type { ISpot } from '../selection';
2
3
  export interface IFireEventParams {
3
4
  event: RMN_SPOT_EVENT;
4
5
  eventUrl: string;
5
6
  }
7
+ export interface IMountedEvent {
8
+ placementId: string;
9
+ spotId: string;
10
+ spotType: string;
11
+ spotVariant: string;
12
+ element: HTMLElement;
13
+ }
14
+ export interface IUnMountedEvent {
15
+ placementId: string;
16
+ spotId: string;
17
+ }
18
+ export interface IResizedEvent {
19
+ placementId: string;
20
+ spotId: string;
21
+ scale: number;
22
+ previousDimensions: {
23
+ width: number;
24
+ height: number;
25
+ };
26
+ currentDimensions: {
27
+ width: number;
28
+ height: number;
29
+ };
30
+ }
31
+ export interface IClickEvent {
32
+ placementId: string;
33
+ spotId: string;
34
+ element: HTMLElement;
35
+ }
36
+ export interface IImpressionEvent {
37
+ placementId: string;
38
+ spotId: string;
39
+ element: HTMLElement;
40
+ }
41
+ export interface IAddToCartEvent {
42
+ placementId: string;
43
+ spotId: string;
44
+ }
45
+ export interface IAddToWishlistEvent {
46
+ placementId: string;
47
+ spotId: string;
48
+ }
49
+ export interface IPurchaseEvent {
50
+ placementId: string;
51
+ spotId: string;
52
+ }
53
+ export interface IBuyNowEvent {
54
+ placementId: string;
55
+ spotId: string;
56
+ }
57
+ export interface IEventMap {
58
+ [RMN_SPOT_EVENT.MOUNTED]: IMountedEvent;
59
+ [RMN_SPOT_EVENT.UNMOUNTED]: IUnMountedEvent;
60
+ [RMN_SPOT_EVENT.RESIZED]: IResizedEvent;
61
+ [RMN_SPOT_EVENT.CLICK]: IClickEvent;
62
+ [RMN_SPOT_EVENT.IMPRESSION]: IImpressionEvent;
63
+ [RMN_SPOT_EVENT.ADD_TO_CART]: IAddToCartEvent;
64
+ [RMN_SPOT_EVENT.ADD_TO_WISHLIST]: IAddToWishlistEvent;
65
+ [RMN_SPOT_EVENT.PURCHASE]: IPurchaseEvent;
66
+ [RMN_SPOT_EVENT.BUY_NOW]: IBuyNowEvent;
67
+ }
68
+ export interface IRegisterSpotParams {
69
+ placementId: string;
70
+ element: HTMLElement;
71
+ spot: ISpot;
72
+ }
@@ -1,5 +1,30 @@
1
- import type { IFireEventParams } from './event.interface';
1
+ import type { IEventMap, IRegisterSpotParams } from './event.interface';
2
2
  export declare class EventService {
3
- fireEvent({ event, eventUrl }: IFireEventParams): Promise<void>;
3
+ private static instance;
4
+ private pubSub;
5
+ private intersectionObserver;
6
+ private activeSpots;
7
+ private constructor();
8
+ static getInstance(): EventService;
9
+ registerSpot({ placementId, element, spot }: IRegisterSpotParams): void;
10
+ unregisterSpot(spotId: string): void;
11
+ private handleIntersectionObserver;
12
+ subscribe<K extends keyof IEventMap>(eventType: K, callback: (data: IEventMap[K]) => void): () => void;
13
+ publish<K extends keyof IEventMap>(eventType: K, data: IEventMap[K]): void;
14
+ /**
15
+ * Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
16
+ *
17
+ * @param {IFireEventParams} params - The parameters for firing the event.
18
+ * @param {RMN_SPOT_EVENT} params.event - The event type.
19
+ * @param {string} params.eventUrl - The URL to which the event is sent.
20
+ * @returns {Promise<void>} - A promise that resolves when the event is fired.
21
+ */
22
+ private fireEvent;
23
+ /**
24
+ * Extracts and decodes a URL from a base64-encoded query parameter.
25
+ *
26
+ * @param {string} url - The URL containing the base64-encoded query parameter.
27
+ * @returns {string} - The decoded URL or an empty string if decoding fails.
28
+ */
4
29
  private getRedirectUrlFromPayload;
5
30
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Callback function type for event subscribers
3
+ * @template T The type of data the callback receives
4
+ */
5
+ export type PSCallback<T> = (data: T) => void;
6
+ /**
7
+ * Function type for unsubscribing from an event
8
+ */
9
+ export type PSUnsubscribe = () => void;
10
+ /**
11
+ * PubSub class
12
+ * Manages event subscriptions and publications
13
+ * @template IEventMap A record type defining the structure of events and their data
14
+ */
15
+ export declare class PubSub<IEventMap> {
16
+ /**
17
+ * Object to store subscribers for each event type
18
+ */
19
+ private subscribers;
20
+ /**
21
+ * Subscribe to an event
22
+ * @param eventType - The type of event to subscribe to
23
+ * @param callback - The function to be called when the event is published
24
+ * @returns A function to unsubscribe from the event
25
+ *
26
+ * @Example:
27
+ * const unsubscribe = pubSub.subscribe('userLogin', (data) => {
28
+ * console.log(`User ${data.username} logged in`);
29
+ * });
30
+ */
31
+ subscribe<K extends keyof IEventMap>(eventType: K, callback: PSCallback<IEventMap[K]>): PSUnsubscribe;
32
+ /**
33
+ * Publish an event
34
+ * @param eventType - The type of event to publish
35
+ * @param data - The data to be passed to the event subscribers
36
+ *
37
+ * @Example:
38
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
39
+ */
40
+ publish<K extends keyof IEventMap>(eventType: K, data: IEventMap[K]): void;
41
+ }
42
+ /**
43
+ * Usage Example:
44
+ *
45
+ * interface IEventMap {
46
+ * userLogin: { username: string; timestamp: number };
47
+ * pageView: { url: string; timestamp: number };
48
+ * }
49
+ *
50
+ * const pubSub = new PubSub<IEventMap>();
51
+ *
52
+ * // Subscribe to events
53
+ * const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
54
+ * console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
55
+ * });
56
+ *
57
+ * pubSub.subscribe('pageView', (data) => {
58
+ * console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
59
+ * });
60
+ *
61
+ * // Publish events
62
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
63
+ * pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
64
+ *
65
+ * // Unsubscribe from an event
66
+ * unsubscribeLogin();
67
+ */
@@ -11,6 +11,7 @@ export interface ISpotEvent {
11
11
  url: string;
12
12
  }
13
13
  export interface ISpot {
14
+ id: string;
14
15
  events: ISpotEvent[];
15
16
  spot: RMN_SPOT_TYPE;
16
17
  variant: SpotVariantType;
@@ -1,10 +1,12 @@
1
1
  import type { IAuthCredentials } from 'modules/auth';
2
2
  import type { IInjectSpotElementParams, IRmnCreateSpotElementConfig } from 'modules/element';
3
+ import { EventService } from 'modules/event';
3
4
  import type { ISpot, ISpots, ISpotSelectionParams } from 'modules/selection';
4
5
  import type { IRmnClient, IRmnConfig } from 'types';
5
6
  export declare class LiquidCommerceRmnClient implements IRmnClient {
6
7
  private readonly selectionService;
7
8
  private readonly elementService;
9
+ private readonly eventService;
8
10
  constructor(auth: IAuthCredentials);
9
11
  /**
10
12
  * Makes a selection request on our server based on the provided data.
@@ -24,6 +26,12 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
24
26
  * @return {Promise<void>} - A promise that resolves when the spot elements are injected.
25
27
  */
26
28
  injectSpotElement(params: IInjectSpotElementParams): Promise<void>;
29
+ /**
30
+ * Returns the event manager instance.
31
+ *
32
+ * @return {EventService} - The event manager instance.
33
+ */
34
+ eventManager(): EventService;
27
35
  /**
28
36
  * Makes a selection request on our server based on the provided data.
29
37
  *
@@ -53,6 +61,7 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
53
61
  * @return {void}
54
62
  */
55
63
  private injectOneSpotElement;
64
+ private eventSpotElement;
56
65
  /**
57
66
  * Prevents duplicate placement ids in the inject data.
58
67
  *
@@ -1,4 +1,6 @@
1
- export type { IInjectSpotElement, IInjectSpotElementConfig, IRmnCreateSpotElementConfig, } from 'modules/element';
1
+ import type { EventService } from './modules/event';
2
+ export type { IInjectSpotElement, IInjectSpotElementConfig, IInjectSpotElementParams, IRmnCreateSpotElementConfig, ISpotColors, ISpotOverlay, } from 'modules/element';
3
+ export type { CarouselNavPositionType, ICarouselButtonOptions, ICarouselDotOptions, ICarouselOptions, } from 'modules/element/component/carousel';
2
4
  export type { ISpots, RmnFilterType, RmnSpotType } from 'modules/selection';
3
5
  export { ISpot, ISpotEvent, ISpotSelectionParams } from 'modules/selection';
4
6
  import type { RMN_ENV } from 'enums';
@@ -7,6 +9,7 @@ import type { ISpots, ISpotSelectionParams } from 'modules/selection';
7
9
  export interface IRmnClient {
8
10
  spotSelection(params: ISpotSelectionParams): Promise<ISpots>;
9
11
  injectSpotElement(params: IInjectSpotElementParams): Promise<void>;
12
+ eventManager(): EventService;
10
13
  }
11
14
  export interface IRmnConfig {
12
15
  env: RMN_ENV;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@liquidcommercedev/rmn-sdk",
3
3
  "description": "LiquidCommerce RMN SDK",
4
4
  "author": "LiquidCommerce Tech",
5
- "version": "1.4.6-beta.4",
5
+ "version": "1.4.6-beta.5",
6
6
  "homepage": "https://docs.liquidcommerce.co/rmn-sdk",
7
7
  "main": "./dist/index.cjs",
8
8
  "module": "./dist/index.esm.js",