@atlaskit/rovo-triggers 7.2.0 → 7.3.0
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/CHANGELOG.md +11 -0
- package/README.md +36 -0
- package/dist/cjs/main.js +87 -31
- package/dist/es2019/main.js +64 -12
- package/dist/esm/main.js +87 -31
- package/dist/types/main.d.ts +4 -2
- package/dist/types/types.d.ts +7 -0
- package/dist/types-ts4.5/main.d.ts +4 -2
- package/dist/types-ts4.5/types.d.ts +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @atlaskit/rovo-triggers
|
|
2
2
|
|
|
3
|
+
## 7.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`8740b2dde71e7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8740b2dde71e7) -
|
|
8
|
+
Add opt-in consume-once pubsub delivery so mounted Rovo Chat listeners can deduplicate action
|
|
9
|
+
events from a single publish.
|
|
10
|
+
- [`925c8d1b15bba`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/925c8d1b15bba) -
|
|
11
|
+
Add optional parameter to exported API: Optional `projectContext` when `chat-open` is emitted in
|
|
12
|
+
the conversation assistant package.
|
|
13
|
+
|
|
3
14
|
## 7.2.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -70,6 +70,42 @@ const YourComponent = () => {
|
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
#### Consume once
|
|
74
|
+
|
|
75
|
+
Publishers can mark an event as `consumeOnce: true` when only one mounted instance of a
|
|
76
|
+
consumer should process that event. Subscribers opt into this behavior with a stable
|
|
77
|
+
`consumeOnceKey`; subscribers sharing the same key will process a `consumeOnce` event once total.
|
|
78
|
+
Subscribers without a `consumeOnceKey` continue to observe the event normally.
|
|
79
|
+
|
|
80
|
+
The delivery id used to deduplicate a publish is generated internally by `rovo-triggers` and is not
|
|
81
|
+
exposed in the event payload. This deduplicates one publish fanout across multiple mounted
|
|
82
|
+
subscribers; separate publish calls are treated as separate events.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const YourComponent = () => {
|
|
86
|
+
useSubscribe({ topic: 'ai-mate', consumeOnceKey: 'your-consumer' }, ({ type, data }) => {
|
|
87
|
+
if(type === 'message-send') {
|
|
88
|
+
sendMessage(data)
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const AnotherComponent = () => {
|
|
96
|
+
const publish = usePublish('ai-mate');
|
|
97
|
+
|
|
98
|
+
const handleClick = () => {
|
|
99
|
+
publish({
|
|
100
|
+
type: 'message-send',
|
|
101
|
+
source: 'my-source',
|
|
102
|
+
consumeOnce: true,
|
|
103
|
+
data: { prompt: 'hello Rovo Chat' },
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
73
109
|
### Subscribe All
|
|
74
110
|
|
|
75
111
|
**Note** - Avoid using this. Right now it's only intended to be a proxy for Rovo Chat to trigger
|
package/dist/cjs/main.js
CHANGED
|
@@ -5,12 +5,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.useSubscribeAll = exports.useSubscribe = exports.usePublish = exports.Subscriber = void 0;
|
|
8
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
|
|
10
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
11
|
var _react = require("react");
|
|
11
12
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
12
13
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
13
14
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
15
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
16
|
+
var MAX_CONSUMED_EVENT_KEYS = 5000;
|
|
14
17
|
var ignoredTriggerLatestEvents = new Set(['editor-context-payload', 'agent-changed',
|
|
15
18
|
// Internal signals that must never overwrite the publish queue — they would
|
|
16
19
|
// cause `triggerLatest` subscribers (e.g. PubSubListener) to replay them
|
|
@@ -27,39 +30,86 @@ var createPubSub = function createPubSub() {
|
|
|
27
30
|
var subscribedEvents = {};
|
|
28
31
|
var publishQueue = {};
|
|
29
32
|
var wildcardEvents = [];
|
|
33
|
+
var consumedEventKeys = new Set();
|
|
34
|
+
var consumedEventKeyQueue = [];
|
|
30
35
|
var subIdCounter = 0;
|
|
36
|
+
var eventIdCounter = 0;
|
|
31
37
|
var generateSubId = function generateSubId() {
|
|
32
38
|
subIdCounter += 1;
|
|
33
39
|
return subIdCounter.toString();
|
|
34
40
|
};
|
|
35
|
-
var
|
|
41
|
+
var createEvent = function createEvent(payload) {
|
|
42
|
+
eventIdCounter += 1;
|
|
43
|
+
return {
|
|
44
|
+
id: eventIdCounter.toString(),
|
|
45
|
+
payload: payload
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
var rememberConsumedEventKey = function rememberConsumedEventKey(claimKey) {
|
|
49
|
+
consumedEventKeys.add(claimKey);
|
|
50
|
+
consumedEventKeyQueue = [].concat((0, _toConsumableArray2.default)(consumedEventKeyQueue), [claimKey]);
|
|
51
|
+
if (consumedEventKeyQueue.length > MAX_CONSUMED_EVENT_KEYS) {
|
|
52
|
+
var _consumedEventKeyQueu = consumedEventKeyQueue,
|
|
53
|
+
_consumedEventKeyQueu2 = (0, _toArray2.default)(_consumedEventKeyQueu),
|
|
54
|
+
oldestClaimKey = _consumedEventKeyQueu2[0],
|
|
55
|
+
remainingClaimKeys = _arrayLikeToArray(_consumedEventKeyQueu2).slice(1);
|
|
56
|
+
consumedEventKeyQueue = remainingClaimKeys;
|
|
57
|
+
if (oldestClaimKey) {
|
|
58
|
+
consumedEventKeys.delete(oldestClaimKey);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var claimConsumeOnceEvent = function claimConsumeOnceEvent(_ref) {
|
|
63
|
+
var event = _ref.event,
|
|
64
|
+
consumeOnceKey = _ref.consumeOnceKey;
|
|
65
|
+
if (!event.payload.consumeOnce || !consumeOnceKey) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
var claimKey = "".concat(consumeOnceKey, ":").concat(event.id);
|
|
69
|
+
if (consumedEventKeys.has(claimKey)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
rememberConsumedEventKey(claimKey);
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
75
|
+
var subscribe = function subscribe(_ref2, callback) {
|
|
36
76
|
var _subscribedEvents$top;
|
|
37
|
-
var topic =
|
|
38
|
-
triggerLatest =
|
|
77
|
+
var topic = _ref2.topic,
|
|
78
|
+
triggerLatest = _ref2.triggerLatest,
|
|
79
|
+
consumeOnceKey = _ref2.consumeOnceKey;
|
|
39
80
|
var events = (_subscribedEvents$top = subscribedEvents[topic]) !== null && _subscribedEvents$top !== void 0 ? _subscribedEvents$top : [];
|
|
40
81
|
var subId = generateSubId();
|
|
41
|
-
var subExists = events.some(function (
|
|
42
|
-
var id =
|
|
82
|
+
var subExists = events.some(function (_ref3) {
|
|
83
|
+
var id = _ref3.id;
|
|
43
84
|
return id === subId;
|
|
44
85
|
});
|
|
86
|
+
var callbackWithConsumption = function callbackWithConsumption(event) {
|
|
87
|
+
if (!claimConsumeOnceEvent({
|
|
88
|
+
event: event,
|
|
89
|
+
consumeOnceKey: consumeOnceKey
|
|
90
|
+
})) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
callback(event.payload);
|
|
94
|
+
};
|
|
45
95
|
|
|
46
96
|
// Push to Topic stack if not already there
|
|
47
97
|
if (!subExists) {
|
|
48
98
|
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, (0, _defineProperty2.default)({}, topic, [].concat((0, _toConsumableArray2.default)(events), [{
|
|
49
|
-
callback:
|
|
99
|
+
callback: callbackWithConsumption,
|
|
50
100
|
id: subId
|
|
51
101
|
}])));
|
|
52
102
|
// If this Topic already has a published event and `triggerLatest` is true, trigger the callback then clear the publishQueue for that Topic
|
|
53
103
|
if (triggerLatest && !!publishQueue[topic]) {
|
|
54
|
-
var
|
|
55
|
-
|
|
104
|
+
var _event = publishQueue[topic];
|
|
105
|
+
callbackWithConsumption(_event);
|
|
56
106
|
delete publishQueue[topic];
|
|
57
107
|
}
|
|
58
108
|
}
|
|
59
109
|
return function () {
|
|
60
110
|
// Remove from Topic stack
|
|
61
|
-
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, (0, _defineProperty2.default)({}, topic, (subscribedEvents[topic] || []).filter(function (
|
|
62
|
-
var id =
|
|
111
|
+
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, (0, _defineProperty2.default)({}, topic, (subscribedEvents[topic] || []).filter(function (_ref4) {
|
|
112
|
+
var id = _ref4.id;
|
|
63
113
|
return id !== subId;
|
|
64
114
|
})));
|
|
65
115
|
};
|
|
@@ -71,26 +121,28 @@ var createPubSub = function createPubSub() {
|
|
|
71
121
|
id: subId
|
|
72
122
|
}]);
|
|
73
123
|
return function () {
|
|
74
|
-
wildcardEvents = wildcardEvents.filter(function (
|
|
75
|
-
var id =
|
|
124
|
+
wildcardEvents = wildcardEvents.filter(function (_ref5) {
|
|
125
|
+
var id = _ref5.id;
|
|
76
126
|
return id !== subId;
|
|
77
127
|
});
|
|
78
128
|
};
|
|
79
129
|
};
|
|
80
130
|
var publish = function publish(topic, payload) {
|
|
131
|
+
var event = createEvent(payload);
|
|
132
|
+
|
|
81
133
|
/**
|
|
82
134
|
* Log that this Topic received a published event, regardless of whether it has subscribers or not.
|
|
83
135
|
* This ensures new subscribers can trigger their callback if `triggerLatest` is true, and the event hasn't already been triggered.
|
|
84
136
|
*/
|
|
85
137
|
// This `ignoredTriggerLatestEvents` is a quick fix to prevent triggering the latest event for certain events
|
|
86
138
|
if (!isIgnoredForTriggerLatest(payload.type)) {
|
|
87
|
-
publishQueue[topic] =
|
|
139
|
+
publishQueue[topic] = event;
|
|
88
140
|
}
|
|
89
141
|
|
|
90
142
|
// Notify `subscribeAll` subscribers as they are Topic agnostic
|
|
91
|
-
wildcardEvents.forEach(function (
|
|
92
|
-
var callback =
|
|
93
|
-
return callback(payload);
|
|
143
|
+
wildcardEvents.forEach(function (_ref6) {
|
|
144
|
+
var callback = _ref6.callback;
|
|
145
|
+
return callback(event.payload);
|
|
94
146
|
});
|
|
95
147
|
var topicSubs = subscribedEvents[topic] || [];
|
|
96
148
|
|
|
@@ -100,9 +152,9 @@ var createPubSub = function createPubSub() {
|
|
|
100
152
|
}
|
|
101
153
|
|
|
102
154
|
// Notify all Topic subscribers of this event
|
|
103
|
-
topicSubs.forEach(function (
|
|
104
|
-
var callback =
|
|
105
|
-
return callback(
|
|
155
|
+
topicSubs.forEach(function (_ref7) {
|
|
156
|
+
var callback = _ref7.callback;
|
|
157
|
+
return callback(event);
|
|
106
158
|
});
|
|
107
159
|
};
|
|
108
160
|
var flushQueue = function flushQueue() {
|
|
@@ -119,9 +171,10 @@ var pubSub = createPubSub();
|
|
|
119
171
|
var usePubSub = function usePubSub() {
|
|
120
172
|
return pubSub;
|
|
121
173
|
};
|
|
122
|
-
var useSubscribe = exports.useSubscribe = function useSubscribe(
|
|
123
|
-
var topic =
|
|
124
|
-
triggerLatest =
|
|
174
|
+
var useSubscribe = exports.useSubscribe = function useSubscribe(_ref8, callback) {
|
|
175
|
+
var topic = _ref8.topic,
|
|
176
|
+
triggerLatest = _ref8.triggerLatest,
|
|
177
|
+
consumeOnceKey = _ref8.consumeOnceKey;
|
|
125
178
|
var _usePubSub = usePubSub(),
|
|
126
179
|
subscribe = _usePubSub.subscribe;
|
|
127
180
|
var callbackRef = (0, _react.useRef)(callback);
|
|
@@ -129,14 +182,15 @@ var useSubscribe = exports.useSubscribe = function useSubscribe(_ref7, callback)
|
|
|
129
182
|
(0, _react.useEffect)(function () {
|
|
130
183
|
var unsubscribe = subscribe({
|
|
131
184
|
topic: topic,
|
|
132
|
-
triggerLatest: triggerLatest
|
|
185
|
+
triggerLatest: triggerLatest,
|
|
186
|
+
consumeOnceKey: consumeOnceKey
|
|
133
187
|
}, function () {
|
|
134
188
|
return callbackRef.current.apply(callbackRef, arguments);
|
|
135
189
|
});
|
|
136
190
|
return unsubscribe;
|
|
137
191
|
},
|
|
138
192
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
139
|
-
[topic]);
|
|
193
|
+
[topic, consumeOnceKey]);
|
|
140
194
|
};
|
|
141
195
|
var useSubscribeAll = exports.useSubscribeAll = function useSubscribeAll(callback) {
|
|
142
196
|
var _usePubSub2 = usePubSub(),
|
|
@@ -172,14 +226,16 @@ var usePublish = exports.usePublish = function usePublish(topic) {
|
|
|
172
226
|
}, [publish, topic]);
|
|
173
227
|
return publishFn;
|
|
174
228
|
};
|
|
175
|
-
var Subscriber = exports.Subscriber = function Subscriber(
|
|
176
|
-
var topic =
|
|
177
|
-
triggerLatest =
|
|
178
|
-
onEvent =
|
|
179
|
-
flushQueueOnUnmount =
|
|
229
|
+
var Subscriber = exports.Subscriber = function Subscriber(_ref9) {
|
|
230
|
+
var topic = _ref9.topic,
|
|
231
|
+
triggerLatest = _ref9.triggerLatest,
|
|
232
|
+
onEvent = _ref9.onEvent,
|
|
233
|
+
flushQueueOnUnmount = _ref9.flushQueueOnUnmount,
|
|
234
|
+
consumeOnceKey = _ref9.consumeOnceKey;
|
|
180
235
|
useSubscribe({
|
|
181
236
|
topic: topic,
|
|
182
|
-
triggerLatest: triggerLatest
|
|
237
|
+
triggerLatest: triggerLatest,
|
|
238
|
+
consumeOnceKey: consumeOnceKey
|
|
183
239
|
}, onEvent);
|
|
184
240
|
useFlushOnUnmount(flushQueueOnUnmount);
|
|
185
241
|
return null;
|
package/dist/es2019/main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
2
2
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
const MAX_CONSUMED_EVENT_KEYS = 5000;
|
|
3
4
|
const ignoredTriggerLatestEvents = new Set(['editor-context-payload', 'agent-changed',
|
|
4
5
|
// Internal signals that must never overwrite the publish queue — they would
|
|
5
6
|
// cause `triggerLatest` subscribers (e.g. PubSubListener) to replay them
|
|
@@ -16,14 +17,50 @@ const createPubSub = () => {
|
|
|
16
17
|
let subscribedEvents = {};
|
|
17
18
|
let publishQueue = {};
|
|
18
19
|
let wildcardEvents = [];
|
|
20
|
+
let consumedEventKeys = new Set();
|
|
21
|
+
let consumedEventKeyQueue = [];
|
|
19
22
|
let subIdCounter = 0;
|
|
23
|
+
let eventIdCounter = 0;
|
|
20
24
|
const generateSubId = () => {
|
|
21
25
|
subIdCounter += 1;
|
|
22
26
|
return subIdCounter.toString();
|
|
23
27
|
};
|
|
28
|
+
const createEvent = payload => {
|
|
29
|
+
eventIdCounter += 1;
|
|
30
|
+
return {
|
|
31
|
+
id: eventIdCounter.toString(),
|
|
32
|
+
payload
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const rememberConsumedEventKey = claimKey => {
|
|
36
|
+
consumedEventKeys.add(claimKey);
|
|
37
|
+
consumedEventKeyQueue = [...consumedEventKeyQueue, claimKey];
|
|
38
|
+
if (consumedEventKeyQueue.length > MAX_CONSUMED_EVENT_KEYS) {
|
|
39
|
+
const [oldestClaimKey, ...remainingClaimKeys] = consumedEventKeyQueue;
|
|
40
|
+
consumedEventKeyQueue = remainingClaimKeys;
|
|
41
|
+
if (oldestClaimKey) {
|
|
42
|
+
consumedEventKeys.delete(oldestClaimKey);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const claimConsumeOnceEvent = ({
|
|
47
|
+
event,
|
|
48
|
+
consumeOnceKey
|
|
49
|
+
}) => {
|
|
50
|
+
if (!event.payload.consumeOnce || !consumeOnceKey) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const claimKey = `${consumeOnceKey}:${event.id}`;
|
|
54
|
+
if (consumedEventKeys.has(claimKey)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
rememberConsumedEventKey(claimKey);
|
|
58
|
+
return true;
|
|
59
|
+
};
|
|
24
60
|
const subscribe = ({
|
|
25
61
|
topic,
|
|
26
|
-
triggerLatest
|
|
62
|
+
triggerLatest,
|
|
63
|
+
consumeOnceKey
|
|
27
64
|
}, callback) => {
|
|
28
65
|
var _subscribedEvents$top;
|
|
29
66
|
const events = (_subscribedEvents$top = subscribedEvents[topic]) !== null && _subscribedEvents$top !== void 0 ? _subscribedEvents$top : [];
|
|
@@ -31,20 +68,29 @@ const createPubSub = () => {
|
|
|
31
68
|
const subExists = events.some(({
|
|
32
69
|
id
|
|
33
70
|
}) => id === subId);
|
|
71
|
+
const callbackWithConsumption = event => {
|
|
72
|
+
if (!claimConsumeOnceEvent({
|
|
73
|
+
event,
|
|
74
|
+
consumeOnceKey
|
|
75
|
+
})) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
callback(event.payload);
|
|
79
|
+
};
|
|
34
80
|
|
|
35
81
|
// Push to Topic stack if not already there
|
|
36
82
|
if (!subExists) {
|
|
37
83
|
subscribedEvents = {
|
|
38
84
|
...subscribedEvents,
|
|
39
85
|
[topic]: [...events, {
|
|
40
|
-
callback,
|
|
86
|
+
callback: callbackWithConsumption,
|
|
41
87
|
id: subId
|
|
42
88
|
}]
|
|
43
89
|
};
|
|
44
90
|
// If this Topic already has a published event and `triggerLatest` is true, trigger the callback then clear the publishQueue for that Topic
|
|
45
91
|
if (triggerLatest && !!publishQueue[topic]) {
|
|
46
|
-
const
|
|
47
|
-
|
|
92
|
+
const event = publishQueue[topic];
|
|
93
|
+
callbackWithConsumption(event);
|
|
48
94
|
delete publishQueue[topic];
|
|
49
95
|
}
|
|
50
96
|
}
|
|
@@ -71,19 +117,21 @@ const createPubSub = () => {
|
|
|
71
117
|
};
|
|
72
118
|
};
|
|
73
119
|
const publish = (topic, payload) => {
|
|
120
|
+
const event = createEvent(payload);
|
|
121
|
+
|
|
74
122
|
/**
|
|
75
123
|
* Log that this Topic received a published event, regardless of whether it has subscribers or not.
|
|
76
124
|
* This ensures new subscribers can trigger their callback if `triggerLatest` is true, and the event hasn't already been triggered.
|
|
77
125
|
*/
|
|
78
126
|
// This `ignoredTriggerLatestEvents` is a quick fix to prevent triggering the latest event for certain events
|
|
79
127
|
if (!isIgnoredForTriggerLatest(payload.type)) {
|
|
80
|
-
publishQueue[topic] =
|
|
128
|
+
publishQueue[topic] = event;
|
|
81
129
|
}
|
|
82
130
|
|
|
83
131
|
// Notify `subscribeAll` subscribers as they are Topic agnostic
|
|
84
132
|
wildcardEvents.forEach(({
|
|
85
133
|
callback
|
|
86
|
-
}) => callback(payload));
|
|
134
|
+
}) => callback(event.payload));
|
|
87
135
|
const topicSubs = subscribedEvents[topic] || [];
|
|
88
136
|
|
|
89
137
|
// If there are no subscribers for this Topic, nothing to do.
|
|
@@ -94,7 +142,7 @@ const createPubSub = () => {
|
|
|
94
142
|
// Notify all Topic subscribers of this event
|
|
95
143
|
topicSubs.forEach(({
|
|
96
144
|
callback
|
|
97
|
-
}) => callback(
|
|
145
|
+
}) => callback(event));
|
|
98
146
|
};
|
|
99
147
|
const flushQueue = () => {
|
|
100
148
|
publishQueue = {};
|
|
@@ -112,7 +160,8 @@ const usePubSub = () => {
|
|
|
112
160
|
};
|
|
113
161
|
export const useSubscribe = ({
|
|
114
162
|
topic,
|
|
115
|
-
triggerLatest
|
|
163
|
+
triggerLatest,
|
|
164
|
+
consumeOnceKey
|
|
116
165
|
}, callback) => {
|
|
117
166
|
const {
|
|
118
167
|
subscribe
|
|
@@ -122,12 +171,13 @@ export const useSubscribe = ({
|
|
|
122
171
|
useEffect(() => {
|
|
123
172
|
const unsubscribe = subscribe({
|
|
124
173
|
topic,
|
|
125
|
-
triggerLatest
|
|
174
|
+
triggerLatest,
|
|
175
|
+
consumeOnceKey
|
|
126
176
|
}, (...args) => callbackRef.current(...args));
|
|
127
177
|
return unsubscribe;
|
|
128
178
|
},
|
|
129
179
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
130
|
-
[topic]);
|
|
180
|
+
[topic, consumeOnceKey]);
|
|
131
181
|
};
|
|
132
182
|
export const useSubscribeAll = callback => {
|
|
133
183
|
const {
|
|
@@ -165,11 +215,13 @@ export const Subscriber = ({
|
|
|
165
215
|
topic,
|
|
166
216
|
triggerLatest,
|
|
167
217
|
onEvent,
|
|
168
|
-
flushQueueOnUnmount
|
|
218
|
+
flushQueueOnUnmount,
|
|
219
|
+
consumeOnceKey
|
|
169
220
|
}) => {
|
|
170
221
|
useSubscribe({
|
|
171
222
|
topic,
|
|
172
|
-
triggerLatest
|
|
223
|
+
triggerLatest,
|
|
224
|
+
consumeOnceKey
|
|
173
225
|
}, onEvent);
|
|
174
226
|
useFlushOnUnmount(flushQueueOnUnmount);
|
|
175
227
|
return null;
|
package/dist/esm/main.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _toArray from "@babel/runtime/helpers/toArray";
|
|
3
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
4
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
5
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
6
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
5
7
|
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
6
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
|
+
var MAX_CONSUMED_EVENT_KEYS = 5000;
|
|
7
10
|
var ignoredTriggerLatestEvents = new Set(['editor-context-payload', 'agent-changed',
|
|
8
11
|
// Internal signals that must never overwrite the publish queue — they would
|
|
9
12
|
// cause `triggerLatest` subscribers (e.g. PubSubListener) to replay them
|
|
@@ -20,39 +23,86 @@ var createPubSub = function createPubSub() {
|
|
|
20
23
|
var subscribedEvents = {};
|
|
21
24
|
var publishQueue = {};
|
|
22
25
|
var wildcardEvents = [];
|
|
26
|
+
var consumedEventKeys = new Set();
|
|
27
|
+
var consumedEventKeyQueue = [];
|
|
23
28
|
var subIdCounter = 0;
|
|
29
|
+
var eventIdCounter = 0;
|
|
24
30
|
var generateSubId = function generateSubId() {
|
|
25
31
|
subIdCounter += 1;
|
|
26
32
|
return subIdCounter.toString();
|
|
27
33
|
};
|
|
28
|
-
var
|
|
34
|
+
var createEvent = function createEvent(payload) {
|
|
35
|
+
eventIdCounter += 1;
|
|
36
|
+
return {
|
|
37
|
+
id: eventIdCounter.toString(),
|
|
38
|
+
payload: payload
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
var rememberConsumedEventKey = function rememberConsumedEventKey(claimKey) {
|
|
42
|
+
consumedEventKeys.add(claimKey);
|
|
43
|
+
consumedEventKeyQueue = [].concat(_toConsumableArray(consumedEventKeyQueue), [claimKey]);
|
|
44
|
+
if (consumedEventKeyQueue.length > MAX_CONSUMED_EVENT_KEYS) {
|
|
45
|
+
var _consumedEventKeyQueu = consumedEventKeyQueue,
|
|
46
|
+
_consumedEventKeyQueu2 = _toArray(_consumedEventKeyQueu),
|
|
47
|
+
oldestClaimKey = _consumedEventKeyQueu2[0],
|
|
48
|
+
remainingClaimKeys = _arrayLikeToArray(_consumedEventKeyQueu2).slice(1);
|
|
49
|
+
consumedEventKeyQueue = remainingClaimKeys;
|
|
50
|
+
if (oldestClaimKey) {
|
|
51
|
+
consumedEventKeys.delete(oldestClaimKey);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var claimConsumeOnceEvent = function claimConsumeOnceEvent(_ref) {
|
|
56
|
+
var event = _ref.event,
|
|
57
|
+
consumeOnceKey = _ref.consumeOnceKey;
|
|
58
|
+
if (!event.payload.consumeOnce || !consumeOnceKey) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
var claimKey = "".concat(consumeOnceKey, ":").concat(event.id);
|
|
62
|
+
if (consumedEventKeys.has(claimKey)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
rememberConsumedEventKey(claimKey);
|
|
66
|
+
return true;
|
|
67
|
+
};
|
|
68
|
+
var subscribe = function subscribe(_ref2, callback) {
|
|
29
69
|
var _subscribedEvents$top;
|
|
30
|
-
var topic =
|
|
31
|
-
triggerLatest =
|
|
70
|
+
var topic = _ref2.topic,
|
|
71
|
+
triggerLatest = _ref2.triggerLatest,
|
|
72
|
+
consumeOnceKey = _ref2.consumeOnceKey;
|
|
32
73
|
var events = (_subscribedEvents$top = subscribedEvents[topic]) !== null && _subscribedEvents$top !== void 0 ? _subscribedEvents$top : [];
|
|
33
74
|
var subId = generateSubId();
|
|
34
|
-
var subExists = events.some(function (
|
|
35
|
-
var id =
|
|
75
|
+
var subExists = events.some(function (_ref3) {
|
|
76
|
+
var id = _ref3.id;
|
|
36
77
|
return id === subId;
|
|
37
78
|
});
|
|
79
|
+
var callbackWithConsumption = function callbackWithConsumption(event) {
|
|
80
|
+
if (!claimConsumeOnceEvent({
|
|
81
|
+
event: event,
|
|
82
|
+
consumeOnceKey: consumeOnceKey
|
|
83
|
+
})) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
callback(event.payload);
|
|
87
|
+
};
|
|
38
88
|
|
|
39
89
|
// Push to Topic stack if not already there
|
|
40
90
|
if (!subExists) {
|
|
41
91
|
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, _defineProperty({}, topic, [].concat(_toConsumableArray(events), [{
|
|
42
|
-
callback:
|
|
92
|
+
callback: callbackWithConsumption,
|
|
43
93
|
id: subId
|
|
44
94
|
}])));
|
|
45
95
|
// If this Topic already has a published event and `triggerLatest` is true, trigger the callback then clear the publishQueue for that Topic
|
|
46
96
|
if (triggerLatest && !!publishQueue[topic]) {
|
|
47
|
-
var
|
|
48
|
-
|
|
97
|
+
var _event = publishQueue[topic];
|
|
98
|
+
callbackWithConsumption(_event);
|
|
49
99
|
delete publishQueue[topic];
|
|
50
100
|
}
|
|
51
101
|
}
|
|
52
102
|
return function () {
|
|
53
103
|
// Remove from Topic stack
|
|
54
|
-
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, _defineProperty({}, topic, (subscribedEvents[topic] || []).filter(function (
|
|
55
|
-
var id =
|
|
104
|
+
subscribedEvents = _objectSpread(_objectSpread({}, subscribedEvents), {}, _defineProperty({}, topic, (subscribedEvents[topic] || []).filter(function (_ref4) {
|
|
105
|
+
var id = _ref4.id;
|
|
56
106
|
return id !== subId;
|
|
57
107
|
})));
|
|
58
108
|
};
|
|
@@ -64,26 +114,28 @@ var createPubSub = function createPubSub() {
|
|
|
64
114
|
id: subId
|
|
65
115
|
}]);
|
|
66
116
|
return function () {
|
|
67
|
-
wildcardEvents = wildcardEvents.filter(function (
|
|
68
|
-
var id =
|
|
117
|
+
wildcardEvents = wildcardEvents.filter(function (_ref5) {
|
|
118
|
+
var id = _ref5.id;
|
|
69
119
|
return id !== subId;
|
|
70
120
|
});
|
|
71
121
|
};
|
|
72
122
|
};
|
|
73
123
|
var publish = function publish(topic, payload) {
|
|
124
|
+
var event = createEvent(payload);
|
|
125
|
+
|
|
74
126
|
/**
|
|
75
127
|
* Log that this Topic received a published event, regardless of whether it has subscribers or not.
|
|
76
128
|
* This ensures new subscribers can trigger their callback if `triggerLatest` is true, and the event hasn't already been triggered.
|
|
77
129
|
*/
|
|
78
130
|
// This `ignoredTriggerLatestEvents` is a quick fix to prevent triggering the latest event for certain events
|
|
79
131
|
if (!isIgnoredForTriggerLatest(payload.type)) {
|
|
80
|
-
publishQueue[topic] =
|
|
132
|
+
publishQueue[topic] = event;
|
|
81
133
|
}
|
|
82
134
|
|
|
83
135
|
// Notify `subscribeAll` subscribers as they are Topic agnostic
|
|
84
|
-
wildcardEvents.forEach(function (
|
|
85
|
-
var callback =
|
|
86
|
-
return callback(payload);
|
|
136
|
+
wildcardEvents.forEach(function (_ref6) {
|
|
137
|
+
var callback = _ref6.callback;
|
|
138
|
+
return callback(event.payload);
|
|
87
139
|
});
|
|
88
140
|
var topicSubs = subscribedEvents[topic] || [];
|
|
89
141
|
|
|
@@ -93,9 +145,9 @@ var createPubSub = function createPubSub() {
|
|
|
93
145
|
}
|
|
94
146
|
|
|
95
147
|
// Notify all Topic subscribers of this event
|
|
96
|
-
topicSubs.forEach(function (
|
|
97
|
-
var callback =
|
|
98
|
-
return callback(
|
|
148
|
+
topicSubs.forEach(function (_ref7) {
|
|
149
|
+
var callback = _ref7.callback;
|
|
150
|
+
return callback(event);
|
|
99
151
|
});
|
|
100
152
|
};
|
|
101
153
|
var flushQueue = function flushQueue() {
|
|
@@ -112,9 +164,10 @@ var pubSub = createPubSub();
|
|
|
112
164
|
var usePubSub = function usePubSub() {
|
|
113
165
|
return pubSub;
|
|
114
166
|
};
|
|
115
|
-
export var useSubscribe = function useSubscribe(
|
|
116
|
-
var topic =
|
|
117
|
-
triggerLatest =
|
|
167
|
+
export var useSubscribe = function useSubscribe(_ref8, callback) {
|
|
168
|
+
var topic = _ref8.topic,
|
|
169
|
+
triggerLatest = _ref8.triggerLatest,
|
|
170
|
+
consumeOnceKey = _ref8.consumeOnceKey;
|
|
118
171
|
var _usePubSub = usePubSub(),
|
|
119
172
|
subscribe = _usePubSub.subscribe;
|
|
120
173
|
var callbackRef = useRef(callback);
|
|
@@ -122,14 +175,15 @@ export var useSubscribe = function useSubscribe(_ref7, callback) {
|
|
|
122
175
|
useEffect(function () {
|
|
123
176
|
var unsubscribe = subscribe({
|
|
124
177
|
topic: topic,
|
|
125
|
-
triggerLatest: triggerLatest
|
|
178
|
+
triggerLatest: triggerLatest,
|
|
179
|
+
consumeOnceKey: consumeOnceKey
|
|
126
180
|
}, function () {
|
|
127
181
|
return callbackRef.current.apply(callbackRef, arguments);
|
|
128
182
|
});
|
|
129
183
|
return unsubscribe;
|
|
130
184
|
},
|
|
131
185
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
132
|
-
[topic]);
|
|
186
|
+
[topic, consumeOnceKey]);
|
|
133
187
|
};
|
|
134
188
|
export var useSubscribeAll = function useSubscribeAll(callback) {
|
|
135
189
|
var _usePubSub2 = usePubSub(),
|
|
@@ -165,14 +219,16 @@ export var usePublish = function usePublish(topic) {
|
|
|
165
219
|
}, [publish, topic]);
|
|
166
220
|
return publishFn;
|
|
167
221
|
};
|
|
168
|
-
export var Subscriber = function Subscriber(
|
|
169
|
-
var topic =
|
|
170
|
-
triggerLatest =
|
|
171
|
-
onEvent =
|
|
172
|
-
flushQueueOnUnmount =
|
|
222
|
+
export var Subscriber = function Subscriber(_ref9) {
|
|
223
|
+
var topic = _ref9.topic,
|
|
224
|
+
triggerLatest = _ref9.triggerLatest,
|
|
225
|
+
onEvent = _ref9.onEvent,
|
|
226
|
+
flushQueueOnUnmount = _ref9.flushQueueOnUnmount,
|
|
227
|
+
consumeOnceKey = _ref9.consumeOnceKey;
|
|
173
228
|
useSubscribe({
|
|
174
229
|
topic: topic,
|
|
175
|
-
triggerLatest: triggerLatest
|
|
230
|
+
triggerLatest: triggerLatest,
|
|
231
|
+
consumeOnceKey: consumeOnceKey
|
|
176
232
|
}, onEvent);
|
|
177
233
|
useFlushOnUnmount(flushQueueOnUnmount);
|
|
178
234
|
return null;
|
package/dist/types/main.d.ts
CHANGED
|
@@ -2,14 +2,16 @@ import type { Callback, Payload, Topic } from './types';
|
|
|
2
2
|
interface SubscribeOptions {
|
|
3
3
|
topic: Topic;
|
|
4
4
|
triggerLatest?: boolean;
|
|
5
|
+
consumeOnceKey?: string;
|
|
5
6
|
}
|
|
6
|
-
export declare const useSubscribe: ({ topic, triggerLatest }: SubscribeOptions, callback: Callback) => void;
|
|
7
|
+
export declare const useSubscribe: ({ topic, triggerLatest, consumeOnceKey }: SubscribeOptions, callback: Callback) => void;
|
|
7
8
|
export declare const useSubscribeAll: (callback: Callback) => void;
|
|
8
9
|
export declare const usePublish: (topic: Topic) => ((payload: Payload) => void);
|
|
9
|
-
export declare const Subscriber: ({ topic, triggerLatest, onEvent, flushQueueOnUnmount, }: {
|
|
10
|
+
export declare const Subscriber: ({ topic, triggerLatest, onEvent, flushQueueOnUnmount, consumeOnceKey, }: {
|
|
10
11
|
topic: Topic;
|
|
11
12
|
triggerLatest?: boolean;
|
|
12
13
|
onEvent: Callback;
|
|
13
14
|
flushQueueOnUnmount?: boolean;
|
|
15
|
+
consumeOnceKey?: string;
|
|
14
16
|
}) => null;
|
|
15
17
|
export {};
|
package/dist/types/types.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ export type PayloadCore<TKey extends string, TData = void> = {
|
|
|
18
18
|
openChatMode?: 'sidebar' | 'mini-modal';
|
|
19
19
|
product?: string;
|
|
20
20
|
interactionSource?: string;
|
|
21
|
+
/**
|
|
22
|
+
* When true, subscribers that opt into the same consumeOnceKey should process this
|
|
23
|
+
* logical event once total. The delivery id used for deduplication is internal to
|
|
24
|
+
* rovo-triggers and is generated for each publish call.
|
|
25
|
+
*/
|
|
26
|
+
consumeOnce?: boolean;
|
|
21
27
|
} & (TData extends void ? {} : {
|
|
22
28
|
data: TData;
|
|
23
29
|
});
|
|
@@ -208,6 +214,7 @@ export type ChatOpenPayload = PayloadCore<'chat-open', {
|
|
|
208
214
|
avatarUrl?: string;
|
|
209
215
|
resetActiveMenu?: boolean;
|
|
210
216
|
openAgentSelector?: boolean;
|
|
217
|
+
aiFeatureContext?: Record<string, unknown>;
|
|
211
218
|
}>;
|
|
212
219
|
export type ForgeAppAuthSuccess = PayloadCore<'forge-auth-success', {
|
|
213
220
|
is3pActionAuth?: boolean;
|
|
@@ -2,14 +2,16 @@ import type { Callback, Payload, Topic } from './types';
|
|
|
2
2
|
interface SubscribeOptions {
|
|
3
3
|
topic: Topic;
|
|
4
4
|
triggerLatest?: boolean;
|
|
5
|
+
consumeOnceKey?: string;
|
|
5
6
|
}
|
|
6
|
-
export declare const useSubscribe: ({ topic, triggerLatest }: SubscribeOptions, callback: Callback) => void;
|
|
7
|
+
export declare const useSubscribe: ({ topic, triggerLatest, consumeOnceKey }: SubscribeOptions, callback: Callback) => void;
|
|
7
8
|
export declare const useSubscribeAll: (callback: Callback) => void;
|
|
8
9
|
export declare const usePublish: (topic: Topic) => ((payload: Payload) => void);
|
|
9
|
-
export declare const Subscriber: ({ topic, triggerLatest, onEvent, flushQueueOnUnmount, }: {
|
|
10
|
+
export declare const Subscriber: ({ topic, triggerLatest, onEvent, flushQueueOnUnmount, consumeOnceKey, }: {
|
|
10
11
|
topic: Topic;
|
|
11
12
|
triggerLatest?: boolean;
|
|
12
13
|
onEvent: Callback;
|
|
13
14
|
flushQueueOnUnmount?: boolean;
|
|
15
|
+
consumeOnceKey?: string;
|
|
14
16
|
}) => null;
|
|
15
17
|
export {};
|
|
@@ -18,6 +18,12 @@ export type PayloadCore<TKey extends string, TData = void> = {
|
|
|
18
18
|
openChatMode?: 'sidebar' | 'mini-modal';
|
|
19
19
|
product?: string;
|
|
20
20
|
interactionSource?: string;
|
|
21
|
+
/**
|
|
22
|
+
* When true, subscribers that opt into the same consumeOnceKey should process this
|
|
23
|
+
* logical event once total. The delivery id used for deduplication is internal to
|
|
24
|
+
* rovo-triggers and is generated for each publish call.
|
|
25
|
+
*/
|
|
26
|
+
consumeOnce?: boolean;
|
|
21
27
|
} & (TData extends void ? {} : {
|
|
22
28
|
data: TData;
|
|
23
29
|
});
|
|
@@ -208,6 +214,7 @@ export type ChatOpenPayload = PayloadCore<'chat-open', {
|
|
|
208
214
|
avatarUrl?: string;
|
|
209
215
|
resetActiveMenu?: boolean;
|
|
210
216
|
openAgentSelector?: boolean;
|
|
217
|
+
aiFeatureContext?: Record<string, unknown>;
|
|
211
218
|
}>;
|
|
212
219
|
export type ForgeAppAuthSuccess = PayloadCore<'forge-auth-success', {
|
|
213
220
|
is3pActionAuth?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/rovo-triggers",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "Provides various trigger events to drive Rovo Chat functionality, such as a publish-subscribe and URL parameter hooks",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"publishConfig": {
|