botframework-webchat-api 4.14.1 → 4.15.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.
Files changed (308) hide show
  1. package/.eslintrc.yml +4 -105
  2. package/.prettierrc.yml +1 -1
  3. package/lib/StyleOptions.d.ts +242 -12
  4. package/lib/StyleOptions.d.ts.map +1 -1
  5. package/lib/defaultStyleOptions.d.ts.map +1 -1
  6. package/lib/defaultStyleOptions.js +67 -14
  7. package/lib/hooks/Composer.d.ts +1 -1
  8. package/lib/hooks/Composer.d.ts.map +1 -1
  9. package/lib/hooks/Composer.js +24 -8
  10. package/lib/hooks/index.d.ts +11 -1
  11. package/lib/hooks/index.d.ts.map +1 -1
  12. package/lib/hooks/index.js +81 -1
  13. package/lib/hooks/internal/useCreateActivityRendererInternal.d.ts.map +1 -1
  14. package/lib/hooks/internal/useCreateActivityRendererInternal.js +1 -1
  15. package/lib/hooks/internal/useDebugDeps.js +10 -4
  16. package/lib/hooks/internal/usePrevious.d.ts +2 -0
  17. package/lib/hooks/internal/usePrevious.d.ts.map +1 -0
  18. package/lib/hooks/internal/usePrevious.js +17 -0
  19. package/lib/hooks/internal/useValueRef.d.ts +3 -0
  20. package/lib/hooks/internal/useValueRef.d.ts.map +1 -0
  21. package/lib/hooks/internal/useValueRef.js +24 -0
  22. package/lib/hooks/middleware/concatMiddleware.d.ts.map +1 -1
  23. package/lib/hooks/middleware/concatMiddleware.js +2 -2
  24. package/lib/hooks/middleware/createDefaultCardActionMiddleware.d.ts.map +1 -1
  25. package/lib/hooks/middleware/createDefaultCardActionMiddleware.js +1 -1
  26. package/lib/hooks/useActivityKeys.d.ts +3 -0
  27. package/lib/hooks/useActivityKeys.d.ts.map +1 -0
  28. package/lib/hooks/useActivityKeys.js +14 -0
  29. package/lib/hooks/useActivityKeysByRead.d.ts +3 -0
  30. package/lib/hooks/useActivityKeysByRead.d.ts.map +1 -0
  31. package/lib/hooks/useActivityKeysByRead.js +14 -0
  32. package/lib/hooks/useCreateActivityStatusRenderer.d.ts.map +1 -1
  33. package/lib/hooks/useCreateActivityStatusRenderer.js +1 -1
  34. package/lib/hooks/useCreateAvatarRenderer.d.ts +4 -2
  35. package/lib/hooks/useCreateAvatarRenderer.d.ts.map +1 -1
  36. package/lib/hooks/useCreateAvatarRenderer.js +1 -1
  37. package/lib/hooks/useDateFormatter.d.ts.map +1 -1
  38. package/lib/hooks/useDateFormatter.js +1 -1
  39. package/lib/hooks/useDebouncedNotifications.js +1 -1
  40. package/lib/hooks/useGetActivityByKey.d.ts +3 -0
  41. package/lib/hooks/useGetActivityByKey.d.ts.map +1 -0
  42. package/lib/hooks/useGetActivityByKey.js +14 -0
  43. package/lib/hooks/useGetHasAcknowledgedByActivityKey.d.ts +3 -0
  44. package/lib/hooks/useGetHasAcknowledgedByActivityKey.d.ts.map +1 -0
  45. package/lib/hooks/useGetHasAcknowledgedByActivityKey.js +14 -0
  46. package/lib/hooks/useGetKeyByActivity.d.ts +3 -0
  47. package/lib/hooks/useGetKeyByActivity.d.ts.map +1 -0
  48. package/lib/hooks/useGetKeyByActivity.js +14 -0
  49. package/lib/hooks/useGetKeyByActivityId.d.ts +3 -0
  50. package/lib/hooks/useGetKeyByActivityId.d.ts.map +1 -0
  51. package/lib/hooks/useGetKeyByActivityId.js +14 -0
  52. package/lib/hooks/useGetSendTimeoutForActivity.d.ts.map +1 -1
  53. package/lib/hooks/useGetSendTimeoutForActivity.js +1 -1
  54. package/lib/hooks/useGroupActivities.d.ts.map +1 -1
  55. package/lib/hooks/useGroupActivities.js +1 -1
  56. package/lib/hooks/useLastAcknowledgedActivityKey.d.ts +3 -0
  57. package/lib/hooks/useLastAcknowledgedActivityKey.d.ts.map +1 -0
  58. package/lib/hooks/useLastAcknowledgedActivityKey.js +14 -0
  59. package/lib/hooks/useLastReadActivityKey.d.ts +3 -0
  60. package/lib/hooks/useLastReadActivityKey.d.ts.map +1 -0
  61. package/lib/hooks/useLastReadActivityKey.js +14 -0
  62. package/lib/hooks/useLocalizer.d.ts +1 -1
  63. package/lib/hooks/useLocalizer.d.ts.map +1 -1
  64. package/lib/hooks/useLocalizer.js +8 -2
  65. package/lib/hooks/useMarkActivityKeyAsRead.d.ts +3 -0
  66. package/lib/hooks/useMarkActivityKeyAsRead.d.ts.map +1 -0
  67. package/lib/hooks/useMarkActivityKeyAsRead.js +14 -0
  68. package/lib/hooks/useMarkAllAsAcknowledged.d.ts +3 -0
  69. package/lib/hooks/useMarkAllAsAcknowledged.d.ts.map +1 -0
  70. package/lib/hooks/useMarkAllAsAcknowledged.js +14 -0
  71. package/lib/hooks/usePerformCardAction.d.ts +2 -2
  72. package/lib/hooks/usePerformCardAction.d.ts.map +1 -1
  73. package/lib/hooks/usePerformCardAction.js +1 -1
  74. package/lib/hooks/useSubmitSendBox.d.ts.map +1 -1
  75. package/lib/hooks/useSubmitSendBox.js +8 -5
  76. package/lib/hooks/utils/ErrorBoundary.js +1 -1
  77. package/lib/index.js +7 -7
  78. package/lib/localization/Localize.d.ts.map +1 -1
  79. package/lib/localization/Localize.js +12 -6
  80. package/lib/localization/ar-SA.json +23 -4
  81. package/lib/localization/bg-BG.json +23 -4
  82. package/lib/localization/ca-ES.json +23 -4
  83. package/lib/localization/cs-CZ.json +23 -4
  84. package/lib/localization/da-DK.json +23 -4
  85. package/lib/localization/de-DE.json +23 -4
  86. package/lib/localization/el-GR.json +23 -4
  87. package/lib/localization/en-US.json +29 -7
  88. package/lib/localization/es-ES.json +23 -4
  89. package/lib/localization/et-EE.json +23 -4
  90. package/lib/localization/eu-ES.json +23 -4
  91. package/lib/localization/fi-FI.json +23 -4
  92. package/lib/localization/fr-FR.json +23 -4
  93. package/lib/localization/gl-ES.json +23 -4
  94. package/lib/localization/he-IL.json +23 -4
  95. package/lib/localization/hi-IN.json +23 -4
  96. package/lib/localization/hr-HR.json +23 -4
  97. package/lib/localization/hu-HU.json +23 -4
  98. package/lib/localization/id-ID.json +23 -4
  99. package/lib/localization/it-IT.json +23 -4
  100. package/lib/localization/ja-JP.json +23 -4
  101. package/lib/localization/kk-KZ.json +23 -4
  102. package/lib/localization/ko-KR.json +23 -4
  103. package/lib/localization/lt-LT.json +23 -4
  104. package/lib/localization/lv-LV.json +23 -4
  105. package/lib/localization/mergeLocalizedStrings.d.ts.map +1 -1
  106. package/lib/localization/mergeLocalizedStrings.js +11 -4
  107. package/lib/localization/ms-MY.json +23 -4
  108. package/lib/localization/nb-NO.json +23 -4
  109. package/lib/localization/nl-NL.json +23 -4
  110. package/lib/localization/pl-PL.json +23 -4
  111. package/lib/localization/pt-BR.json +23 -4
  112. package/lib/localization/pt-PT.json +23 -4
  113. package/lib/localization/ro-RO.json +23 -4
  114. package/lib/localization/ru-RU.json +23 -4
  115. package/lib/localization/sk-SK.json +23 -4
  116. package/lib/localization/sl-SI.json +23 -4
  117. package/lib/localization/sr-Cyrl-CS.json +23 -4
  118. package/lib/localization/sr-Latn-CS.json +23 -4
  119. package/lib/localization/sv-SE.json +23 -4
  120. package/lib/localization/th-TH.json +23 -4
  121. package/lib/localization/tr-TR.json +23 -4
  122. package/lib/localization/uk-UA.json +23 -4
  123. package/lib/localization/vi-VN.json +23 -4
  124. package/lib/localization/yue.json +26 -7
  125. package/lib/localization/zh-CN.json +23 -4
  126. package/lib/localization/zh-HK.json +23 -4
  127. package/lib/localization/zh-TW.json +23 -4
  128. package/lib/normalizeStyleOptions.d.ts.map +1 -1
  129. package/lib/normalizeStyleOptions.js +47 -2
  130. package/lib/patchStyleOptionsFromDeprecatedProps.js +1 -2
  131. package/lib/providers/ActivityAcknowledgement/ActivityAcknowledgementComposer.d.ts +5 -0
  132. package/lib/providers/ActivityAcknowledgement/ActivityAcknowledgementComposer.d.ts.map +1 -0
  133. package/lib/providers/ActivityAcknowledgement/ActivityAcknowledgementComposer.js +184 -0
  134. package/lib/providers/ActivityAcknowledgement/private/Context.d.ts +13 -0
  135. package/lib/providers/ActivityAcknowledgement/private/Context.d.ts.map +1 -0
  136. package/lib/providers/ActivityAcknowledgement/private/Context.js +13 -0
  137. package/lib/providers/ActivityAcknowledgement/private/types.d.ts +6 -0
  138. package/lib/providers/ActivityAcknowledgement/private/types.d.ts.map +1 -0
  139. package/lib/providers/ActivityAcknowledgement/private/types.js +2 -0
  140. package/lib/providers/ActivityAcknowledgement/private/useContext.d.ts +3 -0
  141. package/lib/providers/ActivityAcknowledgement/private/useContext.d.ts.map +1 -0
  142. package/lib/providers/ActivityAcknowledgement/private/useContext.js +24 -0
  143. package/lib/providers/ActivityAcknowledgement/useActivityKeysByRead.d.ts +5 -0
  144. package/lib/providers/ActivityAcknowledgement/useActivityKeysByRead.d.ts.map +1 -0
  145. package/lib/providers/ActivityAcknowledgement/useActivityKeysByRead.js +18 -0
  146. package/lib/providers/ActivityAcknowledgement/useGetHasAcknowledgedByActivityKey.d.ts +2 -0
  147. package/lib/providers/ActivityAcknowledgement/useGetHasAcknowledgedByActivityKey.d.ts.map +1 -0
  148. package/lib/providers/ActivityAcknowledgement/useGetHasAcknowledgedByActivityKey.js +15 -0
  149. package/lib/providers/ActivityAcknowledgement/useLastAcknowledgedActivityKey.d.ts +2 -0
  150. package/lib/providers/ActivityAcknowledgement/useLastAcknowledgedActivityKey.d.ts.map +1 -0
  151. package/lib/providers/ActivityAcknowledgement/useLastAcknowledgedActivityKey.js +15 -0
  152. package/lib/providers/ActivityAcknowledgement/useLastReadActivityKey.d.ts +2 -0
  153. package/lib/providers/ActivityAcknowledgement/useLastReadActivityKey.d.ts.map +1 -0
  154. package/lib/providers/ActivityAcknowledgement/useLastReadActivityKey.js +15 -0
  155. package/lib/providers/ActivityAcknowledgement/useMarkActivityKeyAsRead.d.ts +2 -0
  156. package/lib/providers/ActivityAcknowledgement/useMarkActivityKeyAsRead.d.ts.map +1 -0
  157. package/lib/providers/ActivityAcknowledgement/useMarkActivityKeyAsRead.js +15 -0
  158. package/lib/providers/ActivityAcknowledgement/useMarkAllAsAcknowledged.d.ts +2 -0
  159. package/lib/providers/ActivityAcknowledgement/useMarkAllAsAcknowledged.d.ts.map +1 -0
  160. package/lib/providers/ActivityAcknowledgement/useMarkAllAsAcknowledged.js +15 -0
  161. package/lib/providers/ActivityKeyer/ActivityKeyerComposer.d.ts +18 -0
  162. package/lib/providers/ActivityKeyer/ActivityKeyerComposer.d.ts.map +1 -0
  163. package/lib/providers/ActivityKeyer/ActivityKeyerComposer.js +153 -0
  164. package/lib/providers/ActivityKeyer/private/Context.d.ts +12 -0
  165. package/lib/providers/ActivityKeyer/private/Context.d.ts.map +1 -0
  166. package/lib/providers/ActivityKeyer/private/Context.js +13 -0
  167. package/lib/providers/ActivityKeyer/private/getActivityId.d.ts +3 -0
  168. package/lib/providers/ActivityKeyer/private/getActivityId.d.ts.map +1 -0
  169. package/lib/providers/ActivityKeyer/private/getActivityId.js +11 -0
  170. package/lib/providers/ActivityKeyer/private/getClientActivityId.d.ts +3 -0
  171. package/lib/providers/ActivityKeyer/private/getClientActivityId.d.ts.map +1 -0
  172. package/lib/providers/ActivityKeyer/private/getClientActivityId.js +13 -0
  173. package/lib/providers/ActivityKeyer/private/uniqueId.d.ts +2 -0
  174. package/lib/providers/ActivityKeyer/private/uniqueId.d.ts.map +1 -0
  175. package/lib/providers/ActivityKeyer/private/uniqueId.js +18 -0
  176. package/lib/providers/ActivityKeyer/private/useContext.d.ts +3 -0
  177. package/lib/providers/ActivityKeyer/private/useContext.d.ts.map +1 -0
  178. package/lib/providers/ActivityKeyer/private/useContext.js +24 -0
  179. package/lib/providers/ActivityKeyer/useActivityKeys.d.ts +2 -0
  180. package/lib/providers/ActivityKeyer/useActivityKeys.d.ts.map +1 -0
  181. package/lib/providers/ActivityKeyer/useActivityKeys.js +15 -0
  182. package/lib/providers/ActivityKeyer/useGetActivityByKey.d.ts +3 -0
  183. package/lib/providers/ActivityKeyer/useGetActivityByKey.d.ts.map +1 -0
  184. package/lib/providers/ActivityKeyer/useGetActivityByKey.js +15 -0
  185. package/lib/providers/ActivityKeyer/useGetKeyByActivity.d.ts +3 -0
  186. package/lib/providers/ActivityKeyer/useGetKeyByActivity.d.ts.map +1 -0
  187. package/lib/providers/ActivityKeyer/useGetKeyByActivity.js +15 -0
  188. package/lib/providers/ActivityKeyer/useGetKeyByActivityId.d.ts +2 -0
  189. package/lib/providers/ActivityKeyer/useGetKeyByActivityId.d.ts.map +1 -0
  190. package/lib/providers/ActivityKeyer/useGetKeyByActivityId.js +15 -0
  191. package/lib/types/CardActionMiddleware.d.ts +3 -1
  192. package/lib/types/CardActionMiddleware.d.ts.map +1 -1
  193. package/lib/utils/createCustomEvent.d.ts.map +1 -1
  194. package/lib/utils/createCustomEvent.js +8 -2
  195. package/lib/utils/findLastIndex.d.ts +2 -0
  196. package/lib/utils/findLastIndex.d.ts.map +1 -0
  197. package/lib/utils/findLastIndex.js +32 -0
  198. package/lib/utils/findMin.js +1 -1
  199. package/lib/utils/mapMap.d.ts.map +1 -1
  200. package/lib/utils/mapMap.js +9 -2
  201. package/lib/utils/randomId.d.ts.map +1 -1
  202. package/lib/utils/randomId.js +1 -1
  203. package/package.json +13 -21
  204. package/src/StyleOptions.ts +293 -12
  205. package/src/defaultStyleOptions.ts +71 -13
  206. package/src/hooks/Composer.tsx +86 -49
  207. package/src/hooks/index.ts +20 -0
  208. package/src/hooks/internal/useCreateActivityRendererInternal.ts +21 -20
  209. package/src/hooks/internal/useDebugDeps.js +9 -2
  210. package/src/hooks/internal/usePrevious.ts +11 -0
  211. package/src/hooks/internal/useValueRef.ts +21 -0
  212. package/src/hooks/middleware/concatMiddleware.ts +6 -4
  213. package/src/hooks/middleware/createDefaultCardActionMiddleware.ts +29 -27
  214. package/src/hooks/useActivityKeys.ts +3 -0
  215. package/src/hooks/useActivityKeysByRead.ts +3 -0
  216. package/src/hooks/useCreateActivityStatusRenderer.tsx +10 -13
  217. package/src/hooks/useCreateAvatarRenderer.ts +23 -19
  218. package/src/hooks/useDateFormatter.ts +4 -3
  219. package/src/hooks/useGetActivityByKey.ts +3 -0
  220. package/src/hooks/useGetHasAcknowledgedByActivityKey.ts +3 -0
  221. package/src/hooks/useGetKeyByActivity.ts +3 -0
  222. package/src/hooks/useGetKeyByActivityId.ts +3 -0
  223. package/src/hooks/useGetSendTimeoutForActivity.ts +7 -6
  224. package/src/hooks/useGroupActivities.ts +1 -5
  225. package/src/hooks/useLastAcknowledgedActivityKey.ts +3 -0
  226. package/src/hooks/useLastReadActivityKey.ts +3 -0
  227. package/src/hooks/useLocalizer.ts +7 -2
  228. package/src/hooks/useMarkActivityKeyAsRead.ts +3 -0
  229. package/src/hooks/useMarkAllAsAcknowledged.ts +3 -0
  230. package/src/hooks/usePerformCardAction.ts +2 -3
  231. package/src/hooks/useSubmitSendBox.ts +2 -5
  232. package/src/localization/Localize.ts +9 -2
  233. package/src/localization/ar-SA.json +23 -4
  234. package/src/localization/bg-BG.json +23 -4
  235. package/src/localization/ca-ES.json +23 -4
  236. package/src/localization/cs-CZ.json +23 -4
  237. package/src/localization/da-DK.json +23 -4
  238. package/src/localization/de-DE.json +23 -4
  239. package/src/localization/el-GR.json +23 -4
  240. package/src/localization/en-US.json +29 -7
  241. package/src/localization/es-ES.json +23 -4
  242. package/src/localization/et-EE.json +23 -4
  243. package/src/localization/eu-ES.json +23 -4
  244. package/src/localization/fi-FI.json +23 -4
  245. package/src/localization/fr-FR.json +23 -4
  246. package/src/localization/gl-ES.json +23 -4
  247. package/src/localization/he-IL.json +23 -4
  248. package/src/localization/hi-IN.json +23 -4
  249. package/src/localization/hr-HR.json +23 -4
  250. package/src/localization/hu-HU.json +23 -4
  251. package/src/localization/id-ID.json +23 -4
  252. package/src/localization/it-IT.json +23 -4
  253. package/src/localization/ja-JP.json +23 -4
  254. package/src/localization/kk-KZ.json +23 -4
  255. package/src/localization/ko-KR.json +23 -4
  256. package/src/localization/lt-LT.json +23 -4
  257. package/src/localization/lv-LV.json +23 -4
  258. package/src/localization/mergeLocalizedStrings.ts +7 -1
  259. package/src/localization/ms-MY.json +23 -4
  260. package/src/localization/nb-NO.json +23 -4
  261. package/src/localization/nl-NL.json +23 -4
  262. package/src/localization/pl-PL.json +23 -4
  263. package/src/localization/pt-BR.json +23 -4
  264. package/src/localization/pt-PT.json +23 -4
  265. package/src/localization/ro-RO.json +23 -4
  266. package/src/localization/ru-RU.json +23 -4
  267. package/src/localization/sk-SK.json +23 -4
  268. package/src/localization/sl-SI.json +23 -4
  269. package/src/localization/sr-Cyrl-CS.json +23 -4
  270. package/src/localization/sr-Latn-CS.json +23 -4
  271. package/src/localization/sv-SE.json +23 -4
  272. package/src/localization/th-TH.json +23 -4
  273. package/src/localization/tr-TR.json +23 -4
  274. package/src/localization/uk-UA.json +23 -4
  275. package/src/localization/vi-VN.json +23 -4
  276. package/src/localization/yue.json +26 -7
  277. package/src/localization/zh-CN.json +23 -4
  278. package/src/localization/zh-HK.json +23 -4
  279. package/src/localization/zh-TW.json +23 -4
  280. package/src/normalizeStyleOptions.ts +70 -0
  281. package/src/patchStyleOptionsFromDeprecatedProps.js +0 -2
  282. package/src/providers/ActivityAcknowledgement/ActivityAcknowledgementComposer.tsx +180 -0
  283. package/src/providers/ActivityAcknowledgement/private/Context.ts +18 -0
  284. package/src/providers/ActivityAcknowledgement/private/types.ts +6 -0
  285. package/src/providers/ActivityAcknowledgement/private/useContext.ts +19 -0
  286. package/src/providers/ActivityAcknowledgement/useActivityKeysByRead.tsx +8 -0
  287. package/src/providers/ActivityAcknowledgement/useGetHasAcknowledgedByActivityKey.ts +5 -0
  288. package/src/providers/ActivityAcknowledgement/useLastAcknowledgedActivityKey.ts +5 -0
  289. package/src/providers/ActivityAcknowledgement/useLastReadActivityKey.ts +5 -0
  290. package/src/providers/ActivityAcknowledgement/useMarkActivityKeyAsRead.ts +5 -0
  291. package/src/providers/ActivityAcknowledgement/useMarkAllAsAcknowledged.ts +5 -0
  292. package/src/providers/ActivityKeyer/ActivityKeyerComposer.tsx +151 -0
  293. package/src/providers/ActivityKeyer/private/Context.ts +14 -0
  294. package/src/providers/ActivityKeyer/private/getActivityId.ts +5 -0
  295. package/src/providers/ActivityKeyer/private/getClientActivityId.ts +5 -0
  296. package/src/providers/ActivityKeyer/private/uniqueId.ts +8 -0
  297. package/src/providers/ActivityKeyer/private/useContext.ts +15 -0
  298. package/src/providers/ActivityKeyer/useActivityKeys.ts +5 -0
  299. package/src/providers/ActivityKeyer/useGetActivityByKey.ts +7 -0
  300. package/src/providers/ActivityKeyer/useGetKeyByActivity.ts +7 -0
  301. package/src/providers/ActivityKeyer/useGetKeyByActivityId.ts +5 -0
  302. package/src/types/CardActionMiddleware.ts +1 -1
  303. package/src/utils/createCustomEvent.ts +7 -1
  304. package/src/utils/findLastIndex.spec.js +31 -0
  305. package/src/utils/findLastIndex.ts +11 -0
  306. package/src/utils/mapMap.ts +7 -1
  307. package/src/utils/randomId.ts +1 -1
  308. package/.eslintignore +0 -1
@@ -0,0 +1,151 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, { useCallback, useMemo, useRef } from 'react';
3
+
4
+ import type { DirectLineActivity } from 'botframework-webchat-core';
5
+ import type { FC } from 'react';
6
+
7
+ import ActivityKeyerContext, { ActivityKeyerContextType } from './private/Context';
8
+ import getActivityId from './private/getActivityId';
9
+ import getClientActivityId from './private/getClientActivityId';
10
+ import uniqueId from './private/uniqueId';
11
+ import useActivities from '../../hooks/useActivities';
12
+ import useActivityKeyerContext from './private/useContext';
13
+
14
+ type ActivityIdToKeyMap = Map<string, string>;
15
+ type ActivityToKeyMap = Map<DirectLineActivity, string>;
16
+ type ClientActivityIdToKeyMap = Map<string, string>;
17
+ type KeyToActivityMap = Map<string, DirectLineActivity>;
18
+
19
+ /**
20
+ * React context composer component to assign a perma-key to every activity.
21
+ * This will support both `useGetActivityByKey` and `useGetKeyByActivity` custom hooks.
22
+ *
23
+ * Today, `activity.id` is only guaranteed for activity from others.
24
+ * Not all activities sent by the local user has `activity.id`.
25
+ *
26
+ * To track outgoing activities, we added `activity.channelData.clientActivityId`.
27
+ *
28
+ * This component will create a local key, which can be used to track both
29
+ * incoming and outgoing activities in a consistent way.
30
+ *
31
+ * Local key are only persisted in memory. On refresh, they will be a new random key.
32
+ */
33
+ const ActivityKeyerComposer: FC<{}> = ({ children }) => {
34
+ const existingContext = useActivityKeyerContext(false);
35
+
36
+ if (existingContext) {
37
+ throw new Error('botframework-webchat internal: <ActivityKeyerComposer> should not be nested.');
38
+ }
39
+
40
+ const [activities] = useActivities();
41
+ const activityIdToKeyMapRef = useRef<Readonly<ActivityIdToKeyMap>>(Object.freeze(new Map()));
42
+ const activityToKeyMapRef = useRef<Readonly<ActivityToKeyMap>>(Object.freeze(new Map()));
43
+ const clientActivityIdToKeyMapRef = useRef<Readonly<ClientActivityIdToKeyMap>>(Object.freeze(new Map()));
44
+ const keyToActivityMapRef = useRef<Readonly<KeyToActivityMap>>(Object.freeze(new Map()));
45
+
46
+ // TODO: [P1] `useMemoWithPrevious` to check and cache the resulting array if it hasn't changed.
47
+ const activityKeysState = useMemo<readonly [readonly string[]]>(() => {
48
+ const { current: activityIdToKeyMap } = activityIdToKeyMapRef;
49
+ const { current: activityToKeyMap } = activityToKeyMapRef;
50
+ const { current: clientActivityIdToKeyMap } = clientActivityIdToKeyMapRef;
51
+ const nextActivityIdToKeyMap: ActivityIdToKeyMap = new Map();
52
+ const nextActivityKeys: string[] = [];
53
+ const nextActivityToKeyMap: ActivityToKeyMap = new Map();
54
+ const nextClientActivityIdToKeyMap: ClientActivityIdToKeyMap = new Map();
55
+ const nextKeyToActivityMap: KeyToActivityMap = new Map();
56
+
57
+ activities.forEach(activity => {
58
+ const activityId = getActivityId(activity);
59
+ const clientActivityId = getClientActivityId(activity);
60
+
61
+ const key =
62
+ (clientActivityId && clientActivityIdToKeyMap.get(clientActivityId)) ||
63
+ (activityId && activityIdToKeyMap.get(activityId)) ||
64
+ activityToKeyMap.get(activity) ||
65
+ uniqueId();
66
+
67
+ activityId && nextActivityIdToKeyMap.set(activityId, key);
68
+ clientActivityId && nextClientActivityIdToKeyMap.set(clientActivityId, key);
69
+ nextActivityToKeyMap.set(activity, key);
70
+ nextKeyToActivityMap.set(key, activity);
71
+ nextActivityKeys.push(key);
72
+ });
73
+
74
+ activityIdToKeyMapRef.current = Object.freeze(nextActivityIdToKeyMap);
75
+ activityToKeyMapRef.current = Object.freeze(nextActivityToKeyMap);
76
+ clientActivityIdToKeyMapRef.current = Object.freeze(nextClientActivityIdToKeyMap);
77
+ keyToActivityMapRef.current = Object.freeze(nextKeyToActivityMap);
78
+
79
+ // `nextActivityKeys` could potentially same as `prevActivityKeys` despite reference differences, we should memoize it.
80
+ return Object.freeze([Object.freeze(nextActivityKeys)]) as readonly [readonly string[]];
81
+ }, [activities, activityIdToKeyMapRef, activityToKeyMapRef, clientActivityIdToKeyMapRef, keyToActivityMapRef]);
82
+
83
+ const getActivityByKey: (key?: string) => DirectLineActivity | undefined = useCallback(
84
+ (key?: string): DirectLineActivity | undefined => key && keyToActivityMapRef.current.get(key),
85
+ [keyToActivityMapRef]
86
+ );
87
+
88
+ const getKeyByActivity: (activity?: DirectLineActivity) => string | undefined = useCallback(
89
+ (activity?: DirectLineActivity) => activity && activityToKeyMapRef.current.get(activity),
90
+ [activityToKeyMapRef]
91
+ );
92
+
93
+ const getKeyByActivityId: (activityId?: string) => string | undefined = useCallback(
94
+ (activityId?: string) => activityId && activityIdToKeyMapRef.current.get(activityId),
95
+ [activityIdToKeyMapRef]
96
+ );
97
+
98
+ const contextValue = useMemo<ActivityKeyerContextType>(
99
+ () => ({
100
+ activityKeysState,
101
+ getActivityByKey,
102
+ getKeyByActivity,
103
+ getKeyByActivityId
104
+ }),
105
+ [activityKeysState, getActivityByKey, getKeyByActivity, getKeyByActivityId]
106
+ );
107
+
108
+ const { length: numActivities } = activities;
109
+
110
+ if (activityIdToKeyMapRef.current.size > numActivities) {
111
+ console.warn(
112
+ 'botframework-webchat internal assertion: "activityIdToKeyMap.size" should be equal or less than "activities.length".'
113
+ );
114
+ }
115
+
116
+ if (activityToKeyMapRef.current.size !== numActivities) {
117
+ console.warn(
118
+ 'botframework-webchat internal assertion: "activityToKeyMap.size" should be same as "activities.length".'
119
+ );
120
+ }
121
+
122
+ if (clientActivityIdToKeyMapRef.current.size > numActivities) {
123
+ console.warn(
124
+ 'botframework-webchat internal assertion: "clientActivityIdToKeyMap.size" should be equal or less than "activities.length".'
125
+ );
126
+ }
127
+
128
+ if (keyToActivityMapRef.current.size !== numActivities) {
129
+ console.warn(
130
+ 'botframework-webchat internal assertion: "keyToActivityMap.size" should be same as "activities.length".'
131
+ );
132
+ }
133
+
134
+ if (activityKeysState[0].length !== numActivities) {
135
+ console.warn(
136
+ 'botframework-webchat internal assertion: "activityKeys.length" should be same as "activities.length".'
137
+ );
138
+ }
139
+
140
+ return <ActivityKeyerContext.Provider value={contextValue}>{children}</ActivityKeyerContext.Provider>;
141
+ };
142
+
143
+ ActivityKeyerComposer.defaultProps = {
144
+ children: undefined
145
+ };
146
+
147
+ ActivityKeyerComposer.propTypes = {
148
+ children: PropTypes.any
149
+ };
150
+
151
+ export default ActivityKeyerComposer;
@@ -0,0 +1,14 @@
1
+ import { createContext } from 'react';
2
+
3
+ import type { DirectLineActivity } from 'botframework-webchat-core';
4
+
5
+ type ActivityKeyerContextType = {
6
+ activityKeysState: readonly [readonly string[]];
7
+ getActivityByKey: (key?: string) => DirectLineActivity | undefined;
8
+ getKeyByActivity: (activity?: DirectLineActivity) => string | undefined;
9
+ getKeyByActivityId: (activityKey?: string) => string | undefined;
10
+ };
11
+
12
+ export default createContext<ActivityKeyerContextType>(undefined);
13
+
14
+ export type { ActivityKeyerContextType };
@@ -0,0 +1,5 @@
1
+ import type { DirectLineActivity } from 'botframework-webchat-core';
2
+
3
+ export default function getActivityId(activity: DirectLineActivity): string {
4
+ return activity.id;
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { DirectLineActivity } from 'botframework-webchat-core';
2
+
3
+ export default function getClientActivityId(activity: DirectLineActivity): string {
4
+ return activity.channelData?.clientActivityID;
5
+ }
@@ -0,0 +1,8 @@
1
+ import random from 'math-random';
2
+
3
+ // This format ID must be compatible with HTML "className" and "id" attribute.
4
+ // It will be suffixed as "webchat__activity--{id}".
5
+ export default function uniqueId(): string {
6
+ // eslint-disable-next-line no-magic-numbers
7
+ return random().toString(36).substring(2, 7);
8
+ }
@@ -0,0 +1,15 @@
1
+ import { useContext } from 'react';
2
+
3
+ import ActivityKeyerContext from './Context';
4
+
5
+ import type { ActivityKeyerContextType } from './Context';
6
+
7
+ export default function useActivityKeyerContext(thrownOnUndefined = true): ActivityKeyerContextType {
8
+ const contextValue = useContext(ActivityKeyerContext);
9
+
10
+ if (thrownOnUndefined && !contextValue) {
11
+ throw new Error('botframework-webchat internal: This hook can only be used under <ActivityKeyerComposer>.');
12
+ }
13
+
14
+ return contextValue;
15
+ }
@@ -0,0 +1,5 @@
1
+ import useActivityKeyerContext from './private/useContext';
2
+
3
+ export default function useActivityKeys(): readonly [readonly string[]] {
4
+ return useActivityKeyerContext().activityKeysState;
5
+ }
@@ -0,0 +1,7 @@
1
+ import type { DirectLineActivity } from 'botframework-webchat-core';
2
+
3
+ import useActivityKeyerContext from './private/useContext';
4
+
5
+ export default function useGetActivityByKey(): (key?: string) => DirectLineActivity | undefined {
6
+ return useActivityKeyerContext().getActivityByKey;
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { DirectLineActivity } from 'botframework-webchat-core';
2
+
3
+ import useActivityKeyerContext from './private/useContext';
4
+
5
+ export default function useGetKeyByActivity(): (activity?: DirectLineActivity) => string | undefined {
6
+ return useActivityKeyerContext().getKeyByActivity;
7
+ }
@@ -0,0 +1,5 @@
1
+ import useActivityKeyerContext from './private/useContext';
2
+
3
+ export default function useGetKeyByActivityId(): (activityId?: string) => string | undefined {
4
+ return useActivityKeyerContext().getKeyByActivityId;
5
+ }
@@ -2,7 +2,7 @@ import { DirectLineCardAction } from 'botframework-webchat-core';
2
2
 
3
3
  import FunctionMiddleware from './FunctionMiddleware';
4
4
 
5
- type PerformCardAction = (cardAction: DirectLineCardAction) => void;
5
+ type PerformCardAction = (cardAction: DirectLineCardAction, { target: EventTarget }?) => void;
6
6
 
7
7
  type CardActionMiddleware = FunctionMiddleware<
8
8
  [{ dispatch: (action: any) => void }],
@@ -1,3 +1,5 @@
1
+ import { isForbiddenPropertyName } from 'botframework-webchat-core';
2
+
1
3
  export default function createCustomEvent<T>(
2
4
  name: string,
3
5
  eventInitDict: T
@@ -15,7 +17,11 @@ export default function createCustomEvent<T>(
15
17
  }
16
18
 
17
19
  Object.entries(eventInitDict).forEach(([key, value]) => {
18
- event[key] = value;
20
+ if (!isForbiddenPropertyName(key)) {
21
+ // Mitigation through denylisting.
22
+ // eslint-disable-next-line security/detect-object-injection
23
+ event[key] = value;
24
+ }
19
25
  });
20
26
 
21
27
  return event as any;
@@ -0,0 +1,31 @@
1
+ /* eslint no-magic-numbers: "off" */
2
+
3
+ import findLastIndex from './findLastIndex';
4
+
5
+ describe('find last index', () => {
6
+ test('of an existing element should return the index of last occurrence', () => {
7
+ const actual = findLastIndex([1, 2, 3, 2, 1], value => value === 2);
8
+
9
+ expect(actual).toBe(3);
10
+ });
11
+
12
+ test('of a non-existing element should return -1', () => {
13
+ const actual = findLastIndex([1, 2, 3, 2, 1], value => value === 4);
14
+
15
+ expect(actual).toBe(-1);
16
+ });
17
+
18
+ test('of an empty array should return -1', () => {
19
+ const actual = findLastIndex([], value => value === 1);
20
+
21
+ expect(actual).toBe(-1);
22
+ });
23
+
24
+ test('without a predicate should throw', () => {
25
+ expect(() => findLastIndex([])).toThrowError('not a function');
26
+ });
27
+
28
+ test('without an array should throw', () => {
29
+ expect(() => findLastIndex(undefined, value => value === 1)).toThrowError();
30
+ });
31
+ });
@@ -0,0 +1,11 @@
1
+ export default function findLastIndex<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): number {
2
+ const index = [...array].reverse().findIndex(predicate);
3
+
4
+ if (~index) {
5
+ const { length } = array || [];
6
+
7
+ return length - index - 1;
8
+ }
9
+
10
+ return index;
11
+ }
@@ -1,9 +1,15 @@
1
+ import { isForbiddenPropertyName } from 'botframework-webchat-core';
2
+
1
3
  export default function mapMap<T>(
2
4
  map: { [key: string]: T },
3
5
  mapper: (value: T, key: string) => T
4
6
  ): { [key: string]: T } {
5
7
  return Object.entries(map).reduce((result, [key, value]) => {
6
- result[key] = mapper(value, key);
8
+ if (!isForbiddenPropertyName(key)) {
9
+ // Mitigation through denylisting.
10
+ // eslint-disable-next-line security/detect-object-injection
11
+ result[key] = mapper(value, key);
12
+ }
7
13
 
8
14
  return result;
9
15
  }, {});
@@ -2,6 +2,6 @@
2
2
 
3
3
  import random from 'math-random';
4
4
 
5
- export default function randomId(maxLength: number = 5): string {
5
+ export default function randomId(maxLength = 5): string {
6
6
  return random().toString(36).substr(2, maxLength);
7
7
  }
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- /src/tsconfig.json