@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.
- package/lib/cjs/interfaces/IPostMessageOptions.js +1 -0
- package/lib/cjs/services/BroadcastService.js +33 -2
- package/lib/cjs/services/EventQueue.js +91 -0
- package/lib/esm/interfaces/IPostMessageOptions.js +1 -0
- package/lib/esm/services/BroadcastService.js +29 -2
- package/lib/esm/services/EventQueue.js +83 -0
- package/lib/types/interfaces/ICustomEvent.d.ts +1 -0
- package/lib/types/interfaces/IPostMessageOptions.d.ts +4 -0
- package/lib/types/services/BroadcastService.d.ts +2 -1
- package/lib/types/services/EventQueue.d.ts +17 -0
- package/package.json +2 -2
|
@@ -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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -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.
|
|
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",
|