@microsoft/omnichannel-chat-components 1.1.12 → 1.1.13

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.
@@ -0,0 +1 @@
1
+ "use strict";
@@ -11,6 +11,12 @@ var _operators = require("rxjs/operators");
11
11
 
12
12
  var _broadcastChannel = require("broadcast-channel");
13
13
 
14
+ var _utils = require("../common/utils");
15
+
16
+ var _EventQueue = _interopRequireDefault(require("./EventQueue"));
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+
14
20
  const newMessage = new _rxjs.Subject(); // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
21
 
16
22
  const broadcastServicePubList = {}; // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -20,8 +26,11 @@ const broadcastServiceSubList = {}; // eslint-disable-next-line @typescript-esli
20
26
  let pubChannel; // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
27
 
22
28
  let subChannel;
29
+ let eventQueue;
23
30
 
24
31
  const BroadcastServiceInitialize = channelName => {
32
+ eventQueue = new _EventQueue.default(newMessage);
33
+
25
34
  if (broadcastServicePubList[channelName]) {
26
35
  pubChannel = broadcastServicePubList[channelName];
27
36
  } else {
@@ -41,18 +50,39 @@ const BroadcastServiceInitialize = channelName => {
41
50
 
42
51
  subChannel.onmessage = message => {
43
52
  newMessage.next(message);
53
+ eventQueue.popEvent(message);
54
+ eventQueue.stopIfEmpty();
44
55
  };
45
56
  };
46
57
 
47
58
  exports.BroadcastServiceInitialize = BroadcastServiceInitialize;
48
59
  const BroadcastService = {
49
60
  //broadcast a message
50
- postMessage: message => {
61
+ postMessage: function (message) {
62
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
63
+ retry: true
64
+ };
65
+
51
66
  /**
52
67
  * Omit copying methods to prevent 'DataCloneError' in older browsers when passing an object with functions
53
68
  * This exception occurs when an object can't be clone with the 'structured clone algorithm' (used by postMessage)
54
69
  */
55
- pubChannel.postMessage(JSON.parse(JSON.stringify(message)));
70
+ try {
71
+ const messageCopy = JSON.parse(JSON.stringify(message));
72
+ const eventId = (0, _utils.uuidv4)();
73
+ const event = { ...messageCopy,
74
+ eventId
75
+ };
76
+ eventQueue.pushEvent(event);
77
+ pubChannel.postMessage(event);
78
+ } catch (error) {
79
+ console.error("Error in BroadcastService.postMessage:", error);
80
+ }
81
+
82
+ if (options !== null && options !== void 0 && options.retry) {
83
+ const queueTimeout = (options === null || options === void 0 ? void 0 : options.queueTimeout) || 500;
84
+ eventQueue.startQueue(queueTimeout);
85
+ }
56
86
  },
57
87
  getMessage: message => {
58
88
  return newMessage.pipe((0, _operators.filter)(msg => msg.elementId == message.elementId && msg.elementType == message.elementType && msg.eventName == message.eventName));
@@ -66,6 +96,7 @@ const BroadcastService = {
66
96
  disposeChannel: () => {
67
97
  pubChannel.close();
68
98
  subChannel.close();
99
+ eventQueue.dispose();
69
100
  }
70
101
  };
71
102
  exports.BroadcastService = BroadcastService;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9
+
10
+ class EventQueue {
11
+ constructor(newMessage) {
12
+ _defineProperty(this, "queueing", false);
13
+
14
+ _defineProperty(this, "channelEventQueue", void 0);
15
+
16
+ _defineProperty(this, "queueingId", void 0);
17
+
18
+ _defineProperty(this, "newMessage", void 0);
19
+
20
+ this.channelEventQueue = new Map();
21
+ this.newMessage = newMessage;
22
+ }
23
+
24
+ processEvents() {
25
+ this.channelEventQueue.forEach((event, eventId) => {
26
+ // Process entry based on insertion order
27
+ this.newMessage.next(event); // Post event directly instead of using pubChannel
28
+
29
+ this.channelEventQueue.delete(eventId); // Remove event from queue regardless of outcome
30
+ });
31
+ }
32
+
33
+ queueEvents() {
34
+ let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 500;
35
+ this.stopIfEmpty();
36
+
37
+ if (this.queueingId) {
38
+ // Queueing in progress
39
+ return;
40
+ }
41
+
42
+ if (this.queueing) {
43
+ this.queueingId = setTimeout(() => {
44
+ this.processEvents();
45
+ this.queueEvents(timeout);
46
+ }, timeout);
47
+ }
48
+ }
49
+
50
+ startQueue() {
51
+ let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 500;
52
+ this.queueing = true;
53
+ this.queueEvents(timeout);
54
+ }
55
+
56
+ stopIfEmpty() {
57
+ if (this.channelEventQueue.size === 0) {
58
+ if (this.queueingId) {
59
+ clearTimeout(this.queueingId);
60
+ }
61
+
62
+ this.queueing = false;
63
+ this.queueingId = undefined;
64
+ }
65
+ }
66
+
67
+ pushEvent(event) {
68
+ if (event.eventId) {
69
+ this.channelEventQueue.set(event.eventId, event);
70
+ }
71
+ }
72
+
73
+ popEvent(event) {
74
+ if (event.eventId) {
75
+ this.channelEventQueue.delete(event.eventId);
76
+ }
77
+ }
78
+
79
+ dispose() {
80
+ if (this.queueingId) {
81
+ clearTimeout(this.queueingId);
82
+ this.queueingId = undefined;
83
+ }
84
+
85
+ this.channelEventQueue.clear();
86
+ }
87
+
88
+ }
89
+
90
+ var _default = EventQueue;
91
+ exports.default = _default;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,8 @@
1
1
  import { Subject } from "rxjs";
2
2
  import { filter } from "rxjs/operators";
3
3
  import { BroadcastChannel } from "broadcast-channel";
4
+ import { uuidv4 } from "../common/utils";
5
+ import EventQueue from "./EventQueue";
4
6
  const newMessage = new Subject(); // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
7
 
6
8
  const broadcastServicePubList = {}; // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -10,7 +12,10 @@ const broadcastServiceSubList = {}; // eslint-disable-next-line @typescript-esli
10
12
  let pubChannel; // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
13
 
12
14
  let subChannel;
15
+ let eventQueue;
13
16
  export const BroadcastServiceInitialize = channelName => {
17
+ eventQueue = new EventQueue(newMessage);
18
+
14
19
  if (broadcastServicePubList[channelName]) {
15
20
  pubChannel = broadcastServicePubList[channelName];
16
21
  } else {
@@ -30,16 +35,37 @@ export const BroadcastServiceInitialize = channelName => {
30
35
 
31
36
  subChannel.onmessage = message => {
32
37
  newMessage.next(message);
38
+ eventQueue.popEvent(message);
39
+ eventQueue.stopIfEmpty();
33
40
  };
34
41
  };
35
42
  export const BroadcastService = {
36
43
  //broadcast a message
37
- postMessage: message => {
44
+ postMessage: function (message) {
45
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
46
+ retry: true
47
+ };
48
+
38
49
  /**
39
50
  * Omit copying methods to prevent 'DataCloneError' in older browsers when passing an object with functions
40
51
  * This exception occurs when an object can't be clone with the 'structured clone algorithm' (used by postMessage)
41
52
  */
42
- pubChannel.postMessage(JSON.parse(JSON.stringify(message)));
53
+ try {
54
+ const messageCopy = JSON.parse(JSON.stringify(message));
55
+ const eventId = uuidv4();
56
+ const event = { ...messageCopy,
57
+ eventId
58
+ };
59
+ eventQueue.pushEvent(event);
60
+ pubChannel.postMessage(event);
61
+ } catch (error) {
62
+ console.error("Error in BroadcastService.postMessage:", error);
63
+ }
64
+
65
+ if (options !== null && options !== void 0 && options.retry) {
66
+ const queueTimeout = (options === null || options === void 0 ? void 0 : options.queueTimeout) || 500;
67
+ eventQueue.startQueue(queueTimeout);
68
+ }
43
69
  },
44
70
  getMessage: message => {
45
71
  return newMessage.pipe(filter(msg => msg.elementId == message.elementId && msg.elementType == message.elementType && msg.eventName == message.eventName));
@@ -53,5 +79,6 @@ export const BroadcastService = {
53
79
  disposeChannel: () => {
54
80
  pubChannel.close();
55
81
  subChannel.close();
82
+ eventQueue.dispose();
56
83
  }
57
84
  };
@@ -0,0 +1,83 @@
1
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
+
3
+ class EventQueue {
4
+ constructor(newMessage) {
5
+ _defineProperty(this, "queueing", false);
6
+
7
+ _defineProperty(this, "channelEventQueue", void 0);
8
+
9
+ _defineProperty(this, "queueingId", void 0);
10
+
11
+ _defineProperty(this, "newMessage", void 0);
12
+
13
+ this.channelEventQueue = new Map();
14
+ this.newMessage = newMessage;
15
+ }
16
+
17
+ processEvents() {
18
+ this.channelEventQueue.forEach((event, eventId) => {
19
+ // Process entry based on insertion order
20
+ this.newMessage.next(event); // Post event directly instead of using pubChannel
21
+
22
+ this.channelEventQueue.delete(eventId); // Remove event from queue regardless of outcome
23
+ });
24
+ }
25
+
26
+ queueEvents() {
27
+ let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 500;
28
+ this.stopIfEmpty();
29
+
30
+ if (this.queueingId) {
31
+ // Queueing in progress
32
+ return;
33
+ }
34
+
35
+ if (this.queueing) {
36
+ this.queueingId = setTimeout(() => {
37
+ this.processEvents();
38
+ this.queueEvents(timeout);
39
+ }, timeout);
40
+ }
41
+ }
42
+
43
+ startQueue() {
44
+ let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 500;
45
+ this.queueing = true;
46
+ this.queueEvents(timeout);
47
+ }
48
+
49
+ stopIfEmpty() {
50
+ if (this.channelEventQueue.size === 0) {
51
+ if (this.queueingId) {
52
+ clearTimeout(this.queueingId);
53
+ }
54
+
55
+ this.queueing = false;
56
+ this.queueingId = undefined;
57
+ }
58
+ }
59
+
60
+ pushEvent(event) {
61
+ if (event.eventId) {
62
+ this.channelEventQueue.set(event.eventId, event);
63
+ }
64
+ }
65
+
66
+ popEvent(event) {
67
+ if (event.eventId) {
68
+ this.channelEventQueue.delete(event.eventId);
69
+ }
70
+ }
71
+
72
+ dispose() {
73
+ if (this.queueingId) {
74
+ clearTimeout(this.queueingId);
75
+ this.queueingId = undefined;
76
+ }
77
+
78
+ this.channelEventQueue.clear();
79
+ }
80
+
81
+ }
82
+
83
+ export default EventQueue;
@@ -4,4 +4,5 @@ export interface ICustomEvent {
4
4
  elementType?: ElementType | any;
5
5
  elementId?: string;
6
6
  payload?: any;
7
+ eventId?: string;
7
8
  }
@@ -0,0 +1,4 @@
1
+ export interface IPostMessageOptions {
2
+ retry?: boolean;
3
+ queueTimeout?: number;
4
+ }
@@ -1,8 +1,9 @@
1
1
  import { Subject } from "rxjs";
2
2
  import { ICustomEvent } from "../interfaces/ICustomEvent";
3
+ import { IPostMessageOptions } from "../interfaces/IPostMessageOptions";
3
4
  export declare const BroadcastServiceInitialize: (channelName: string) => void;
4
5
  export declare const BroadcastService: {
5
- postMessage: (message: ICustomEvent) => void;
6
+ postMessage: (message: ICustomEvent, options?: IPostMessageOptions) => void;
6
7
  getMessage: (message: ICustomEvent) => import("rxjs").Observable<ICustomEvent>;
7
8
  getMessageByEventName: (eventName: string) => import("rxjs").Observable<ICustomEvent>;
8
9
  getAnyMessage: () => Subject<ICustomEvent>;
@@ -0,0 +1,17 @@
1
+ import { Subject } from "rxjs";
2
+ import { ICustomEvent } from "../interfaces/ICustomEvent";
3
+ declare class EventQueue {
4
+ private queueing;
5
+ private channelEventQueue;
6
+ private queueingId?;
7
+ private newMessage;
8
+ constructor(newMessage: Subject<ICustomEvent>);
9
+ processEvents(): void;
10
+ queueEvents(timeout?: number): void;
11
+ startQueue(timeout?: number): void;
12
+ stopIfEmpty(): void;
13
+ pushEvent(event: any): void;
14
+ popEvent(event: any): void;
15
+ dispose(): void;
16
+ }
17
+ export default EventQueue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/omnichannel-chat-components",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "Microsoft Omnichannel Chat Components",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/types/index.d.ts",
@@ -32,8 +32,8 @@
32
32
  "@storybook/addon-storyshots": "^6.4.8",
33
33
  "@storybook/react": "^6.4.8",
34
34
  "@storybook/testing-react": "^1.2.1",
35
- "@testing-library/jest-dom": "^5.15.0",
36
35
  "@testing-library/dom": "^10.4.0",
36
+ "@testing-library/jest-dom": "^5.15.0",
37
37
  "@testing-library/react": "^16.3.0",
38
38
  "@types/core-js": "^2.5.5",
39
39
  "@types/jest": "^27.0.2",