repluggable-core 0.0.0-pr280.413 → 0.0.0-pr282.418

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 (328) hide show
  1. package/__tests__/spec-setup.js +3 -0
  2. package/dist/es/{API.d.ts → src/API.d.ts} +31 -10
  3. package/dist/es/src/API.d.ts.map +1 -0
  4. package/dist/es/src/API.js +2 -0
  5. package/dist/es/src/API.js.map +1 -0
  6. package/dist/es/src/IterableWeakMap.d.ts +20 -0
  7. package/dist/es/src/IterableWeakMap.d.ts.map +1 -0
  8. package/dist/es/src/IterableWeakMap.js +92 -0
  9. package/dist/es/src/IterableWeakMap.js.map +1 -0
  10. package/dist/es/src/appHost.d.ts +7 -0
  11. package/dist/es/src/appHost.d.ts.map +1 -0
  12. package/dist/es/src/appHost.js +848 -0
  13. package/dist/es/src/appHost.js.map +1 -0
  14. package/dist/es/src/appHostServices.d.ts +12 -0
  15. package/dist/es/src/appHostServices.d.ts.map +1 -0
  16. package/dist/es/src/appHostServices.js +25 -0
  17. package/dist/es/src/appHostServices.js.map +1 -0
  18. package/dist/es/src/appHostUtils.d.ts +4 -0
  19. package/dist/es/src/appHostUtils.d.ts.map +1 -0
  20. package/dist/es/src/appHostUtils.js +8 -0
  21. package/dist/es/src/appHostUtils.js.map +1 -0
  22. package/dist/es/src/extensionSlot.d.ts +8 -0
  23. package/dist/es/src/extensionSlot.d.ts.map +1 -0
  24. package/dist/es/src/extensionSlot.js +59 -0
  25. package/dist/es/src/extensionSlot.js.map +1 -0
  26. package/dist/es/src/hot.d.ts +14 -0
  27. package/dist/es/src/hot.d.ts.map +1 -0
  28. package/dist/es/src/hot.js +52 -0
  29. package/dist/es/src/hot.js.map +1 -0
  30. package/dist/es/src/index.d.ts +11 -0
  31. package/dist/es/src/index.d.ts.map +1 -0
  32. package/dist/es/src/index.js +10 -0
  33. package/dist/es/src/index.js.map +1 -0
  34. package/dist/es/src/installedShellsState.d.ts +19 -0
  35. package/dist/es/src/installedShellsState.d.ts.map +1 -0
  36. package/dist/es/src/installedShellsState.js +30 -0
  37. package/dist/es/src/installedShellsState.js.map +1 -0
  38. package/dist/es/src/interceptAnyObject.d.ts +7 -0
  39. package/dist/es/src/interceptAnyObject.d.ts.map +1 -0
  40. package/dist/es/src/interceptAnyObject.js +21 -0
  41. package/dist/es/src/interceptAnyObject.js.map +1 -0
  42. package/dist/es/src/interceptEntryPoints.d.ts +6 -0
  43. package/dist/es/src/interceptEntryPoints.d.ts.map +1 -0
  44. package/dist/es/src/interceptEntryPoints.js +22 -0
  45. package/dist/es/src/interceptEntryPoints.js.map +1 -0
  46. package/dist/es/src/invokeSlotCallbacks.d.ts +3 -0
  47. package/dist/es/src/invokeSlotCallbacks.d.ts.map +1 -0
  48. package/dist/es/src/invokeSlotCallbacks.js +20 -0
  49. package/dist/es/src/invokeSlotCallbacks.js.map +1 -0
  50. package/dist/es/src/loggers.d.ts +4 -0
  51. package/dist/es/src/loggers.d.ts.map +1 -0
  52. package/dist/es/src/loggers.js +100 -0
  53. package/dist/es/src/loggers.js.map +1 -0
  54. package/dist/es/src/monitorAPI.d.ts +3 -0
  55. package/dist/es/src/monitorAPI.d.ts.map +1 -0
  56. package/dist/es/src/monitorAPI.js +53 -0
  57. package/dist/es/src/monitorAPI.js.map +1 -0
  58. package/dist/es/src/repluggableAppDebug/index.d.ts +2 -0
  59. package/dist/es/src/repluggableAppDebug/index.d.ts.map +1 -0
  60. package/dist/es/src/repluggableAppDebug/index.js +2 -0
  61. package/dist/es/src/repluggableAppDebug/index.js.map +1 -0
  62. package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
  63. package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
  64. package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js +94 -0
  65. package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
  66. package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
  67. package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
  68. package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js +132 -0
  69. package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
  70. package/dist/es/src/tarjanGraph.d.ts +27 -0
  71. package/dist/es/src/tarjanGraph.d.ts.map +1 -0
  72. package/dist/es/src/tarjanGraph.js +94 -0
  73. package/dist/es/src/tarjanGraph.js.map +1 -0
  74. package/dist/es/src/throttledStore.d.ts +32 -0
  75. package/dist/es/src/throttledStore.d.ts.map +1 -0
  76. package/dist/es/src/throttledStore.js +240 -0
  77. package/dist/es/src/throttledStore.js.map +1 -0
  78. package/dist/es/test/IterableWeakMap.spec.d.ts +2 -0
  79. package/dist/es/test/IterableWeakMap.spec.d.ts.map +1 -0
  80. package/dist/es/test/IterableWeakMap.spec.js +218 -0
  81. package/dist/es/test/IterableWeakMap.spec.js.map +1 -0
  82. package/dist/es/test/appHost.mock.d.ts +4 -0
  83. package/dist/es/test/appHost.mock.d.ts.map +1 -0
  84. package/dist/es/test/appHost.mock.js +54 -0
  85. package/dist/es/test/appHost.mock.js.map +1 -0
  86. package/dist/es/test/appHost.spec.d.ts +2 -0
  87. package/dist/es/test/appHost.spec.d.ts.map +1 -0
  88. package/dist/es/test/appHost.spec.js +1323 -0
  89. package/dist/es/test/appHost.spec.js.map +1 -0
  90. package/dist/es/test/customExtensionSlot.spec.d.ts +2 -0
  91. package/dist/es/test/customExtensionSlot.spec.d.ts.map +1 -0
  92. package/dist/es/test/customExtensionSlot.spec.js +112 -0
  93. package/dist/es/test/customExtensionSlot.spec.js.map +1 -0
  94. package/dist/es/test/extensionSlot.spec.d.ts +2 -0
  95. package/dist/es/test/extensionSlot.spec.d.ts.map +1 -0
  96. package/dist/es/test/extensionSlot.spec.js +73 -0
  97. package/dist/es/test/extensionSlot.spec.js.map +1 -0
  98. package/dist/es/test/installedShellsState.spec.d.ts +2 -0
  99. package/dist/es/test/installedShellsState.spec.d.ts.map +1 -0
  100. package/dist/es/test/installedShellsState.spec.js +28 -0
  101. package/dist/es/test/installedShellsState.spec.js.map +1 -0
  102. package/dist/es/test/interceptAnyObject.spec.d.ts +2 -0
  103. package/dist/es/test/interceptAnyObject.spec.d.ts.map +1 -0
  104. package/dist/es/test/interceptAnyObject.spec.js +166 -0
  105. package/dist/es/test/interceptAnyObject.spec.js.map +1 -0
  106. package/dist/es/test/interceptEntryPoints.spec.d.ts +2 -0
  107. package/dist/es/test/interceptEntryPoints.spec.d.ts.map +1 -0
  108. package/dist/es/test/interceptEntryPoints.spec.js +244 -0
  109. package/dist/es/test/interceptEntryPoints.spec.js.map +1 -0
  110. package/dist/es/test/loggers.spec.d.ts +2 -0
  111. package/dist/es/test/loggers.spec.d.ts.map +1 -0
  112. package/dist/es/test/loggers.spec.js +218 -0
  113. package/dist/es/test/loggers.spec.js.map +1 -0
  114. package/dist/es/test/repluggableAppDebug.spec.d.ts +2 -0
  115. package/dist/es/test/repluggableAppDebug.spec.d.ts.map +1 -0
  116. package/dist/es/test/repluggableAppDebug.spec.js +107 -0
  117. package/dist/es/test/repluggableAppDebug.spec.js.map +1 -0
  118. package/dist/es/test/testKit.spec.d.ts +2 -0
  119. package/dist/es/test/testKit.spec.d.ts.map +1 -0
  120. package/dist/es/test/testKit.spec.js +129 -0
  121. package/dist/es/test/testKit.spec.js.map +1 -0
  122. package/dist/es/testKit/emptyLoggerOptions.d.ts +3 -0
  123. package/dist/es/testKit/emptyLoggerOptions.d.ts.map +1 -0
  124. package/dist/es/testKit/emptyLoggerOptions.js +15 -0
  125. package/dist/es/testKit/emptyLoggerOptions.js.map +1 -0
  126. package/dist/es/testKit/index.d.ts +25 -0
  127. package/dist/es/testKit/index.d.ts.map +1 -0
  128. package/dist/es/testKit/index.js +130 -0
  129. package/dist/es/testKit/index.js.map +1 -0
  130. package/dist/es/testKit/mockPackage.d.ts +21 -0
  131. package/dist/es/testKit/mockPackage.d.ts.map +1 -0
  132. package/dist/es/testKit/mockPackage.js +85 -0
  133. package/dist/es/testKit/mockPackage.js.map +1 -0
  134. package/dist/es/testKit/withConsoleErrors.d.ts +2 -0
  135. package/dist/es/testKit/withConsoleErrors.d.ts.map +1 -0
  136. package/dist/es/testKit/withConsoleErrors.js +12 -0
  137. package/dist/es/testKit/withConsoleErrors.js.map +1 -0
  138. package/dist/es/testKit/withThrowOnError.d.ts +3 -0
  139. package/dist/es/testKit/withThrowOnError.d.ts.map +1 -0
  140. package/dist/es/testKit/withThrowOnError.js +27 -0
  141. package/dist/es/testKit/withThrowOnError.js.map +1 -0
  142. package/dist/src/API.d.ts +31 -10
  143. package/dist/src/API.d.ts.map +1 -1
  144. package/dist/src/API.js +3 -0
  145. package/dist/src/API.js.map +1 -1
  146. package/dist/src/IterableWeakMap.d.ts +20 -0
  147. package/dist/src/IterableWeakMap.d.ts.map +1 -0
  148. package/dist/src/IterableWeakMap.js +96 -0
  149. package/dist/src/IterableWeakMap.js.map +1 -0
  150. package/dist/src/appHost.d.ts +7 -0
  151. package/dist/src/appHost.d.ts.map +1 -0
  152. package/dist/src/appHost.js +856 -0
  153. package/dist/src/appHost.js.map +1 -0
  154. package/dist/src/appHostServices.d.ts +12 -0
  155. package/dist/src/appHostServices.d.ts.map +1 -0
  156. package/dist/src/appHostServices.js +29 -0
  157. package/dist/src/appHostServices.js.map +1 -0
  158. package/dist/src/appHostUtils.d.ts +4 -0
  159. package/dist/src/appHostUtils.d.ts.map +1 -0
  160. package/dist/src/appHostUtils.js +16 -0
  161. package/dist/src/appHostUtils.js.map +1 -0
  162. package/dist/src/extensionSlot.d.ts +8 -0
  163. package/dist/src/extensionSlot.d.ts.map +1 -0
  164. package/dist/src/extensionSlot.js +67 -0
  165. package/dist/src/extensionSlot.js.map +1 -0
  166. package/dist/src/hot.d.ts +14 -0
  167. package/dist/src/hot.d.ts.map +1 -0
  168. package/dist/src/hot.js +56 -0
  169. package/dist/src/hot.js.map +1 -0
  170. package/dist/src/index.d.ts +10 -1
  171. package/dist/src/index.d.ts.map +1 -1
  172. package/dist/src/index.js +23 -0
  173. package/dist/src/index.js.map +1 -1
  174. package/dist/src/installedShellsState.d.ts +19 -0
  175. package/dist/src/installedShellsState.d.ts.map +1 -0
  176. package/dist/src/installedShellsState.js +38 -0
  177. package/dist/src/installedShellsState.js.map +1 -0
  178. package/dist/src/interceptAnyObject.d.ts +7 -0
  179. package/dist/src/interceptAnyObject.d.ts.map +1 -0
  180. package/dist/src/interceptAnyObject.js +28 -0
  181. package/dist/src/interceptAnyObject.js.map +1 -0
  182. package/dist/src/interceptEntryPoints.d.ts +6 -0
  183. package/dist/src/interceptEntryPoints.d.ts.map +1 -0
  184. package/dist/src/interceptEntryPoints.js +30 -0
  185. package/dist/src/interceptEntryPoints.js.map +1 -0
  186. package/dist/src/invokeSlotCallbacks.d.ts +3 -0
  187. package/dist/src/invokeSlotCallbacks.d.ts.map +1 -0
  188. package/dist/src/invokeSlotCallbacks.js +24 -0
  189. package/dist/src/invokeSlotCallbacks.js.map +1 -0
  190. package/dist/src/loggers.d.ts +4 -0
  191. package/dist/src/loggers.d.ts.map +1 -0
  192. package/dist/src/loggers.js +104 -0
  193. package/dist/src/loggers.js.map +1 -0
  194. package/dist/src/monitorAPI.d.ts +3 -0
  195. package/dist/src/monitorAPI.d.ts.map +1 -0
  196. package/dist/src/monitorAPI.js +57 -0
  197. package/dist/src/monitorAPI.js.map +1 -0
  198. package/dist/src/repluggableAppDebug/index.d.ts +2 -0
  199. package/dist/src/repluggableAppDebug/index.d.ts.map +1 -0
  200. package/dist/src/repluggableAppDebug/index.js +6 -0
  201. package/dist/src/repluggableAppDebug/index.js.map +1 -0
  202. package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
  203. package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
  204. package/dist/src/repluggableAppDebug/performanceDebugInfo.js +101 -0
  205. package/dist/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
  206. package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
  207. package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
  208. package/dist/src/repluggableAppDebug/repluggableAppDebug.js +139 -0
  209. package/dist/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
  210. package/dist/src/tarjanGraph.d.ts +27 -0
  211. package/dist/src/tarjanGraph.d.ts.map +1 -0
  212. package/dist/src/tarjanGraph.js +100 -0
  213. package/dist/src/tarjanGraph.js.map +1 -0
  214. package/dist/src/throttledStore.d.ts +32 -0
  215. package/dist/src/throttledStore.d.ts.map +1 -0
  216. package/dist/src/throttledStore.js +249 -0
  217. package/dist/src/throttledStore.js.map +1 -0
  218. package/dist/test/IterableWeakMap.spec.d.ts +2 -0
  219. package/dist/test/IterableWeakMap.spec.d.ts.map +1 -0
  220. package/dist/test/IterableWeakMap.spec.js +220 -0
  221. package/dist/test/IterableWeakMap.spec.js.map +1 -0
  222. package/dist/test/appHost.mock.d.ts +4 -0
  223. package/dist/test/appHost.mock.d.ts.map +1 -0
  224. package/dist/test/appHost.mock.js +59 -0
  225. package/dist/test/appHost.mock.js.map +1 -0
  226. package/dist/test/appHost.spec.d.ts +2 -0
  227. package/dist/test/appHost.spec.d.ts.map +1 -0
  228. package/dist/test/appHost.spec.js +1328 -0
  229. package/dist/test/appHost.spec.js.map +1 -0
  230. package/dist/test/customExtensionSlot.spec.d.ts +2 -0
  231. package/dist/test/customExtensionSlot.spec.d.ts.map +1 -0
  232. package/dist/test/customExtensionSlot.spec.js +117 -0
  233. package/dist/test/customExtensionSlot.spec.js.map +1 -0
  234. package/dist/test/extensionSlot.spec.d.ts +2 -0
  235. package/dist/test/extensionSlot.spec.d.ts.map +1 -0
  236. package/dist/test/extensionSlot.spec.js +75 -0
  237. package/dist/test/extensionSlot.spec.js.map +1 -0
  238. package/dist/test/installedShellsState.spec.d.ts +2 -0
  239. package/dist/test/installedShellsState.spec.d.ts.map +1 -0
  240. package/dist/test/installedShellsState.spec.js +30 -0
  241. package/dist/test/installedShellsState.spec.js.map +1 -0
  242. package/dist/test/interceptAnyObject.spec.d.ts +2 -0
  243. package/dist/test/interceptAnyObject.spec.d.ts.map +1 -0
  244. package/dist/test/interceptAnyObject.spec.js +171 -0
  245. package/dist/test/interceptAnyObject.spec.js.map +1 -0
  246. package/dist/test/interceptEntryPoints.spec.d.ts +2 -0
  247. package/dist/test/interceptEntryPoints.spec.d.ts.map +1 -0
  248. package/dist/test/interceptEntryPoints.spec.js +249 -0
  249. package/dist/test/interceptEntryPoints.spec.js.map +1 -0
  250. package/dist/test/loggers.spec.d.ts +2 -0
  251. package/dist/test/loggers.spec.d.ts.map +1 -0
  252. package/dist/test/loggers.spec.js +220 -0
  253. package/dist/test/loggers.spec.js.map +1 -0
  254. package/dist/test/repluggableAppDebug.spec.d.ts +2 -0
  255. package/dist/test/repluggableAppDebug.spec.d.ts.map +1 -0
  256. package/dist/test/repluggableAppDebug.spec.js +109 -0
  257. package/dist/test/repluggableAppDebug.spec.js.map +1 -0
  258. package/dist/test/testKit.spec.d.ts +2 -0
  259. package/dist/test/testKit.spec.d.ts.map +1 -0
  260. package/dist/test/testKit.spec.js +134 -0
  261. package/dist/test/testKit.spec.js.map +1 -0
  262. package/dist/testKit/emptyLoggerOptions.d.ts +3 -0
  263. package/dist/testKit/emptyLoggerOptions.d.ts.map +1 -0
  264. package/dist/testKit/emptyLoggerOptions.js +18 -0
  265. package/dist/testKit/emptyLoggerOptions.js.map +1 -0
  266. package/dist/testKit/index.d.ts +25 -0
  267. package/dist/testKit/index.d.ts.map +1 -0
  268. package/dist/testKit/index.js +158 -0
  269. package/dist/testKit/index.js.map +1 -0
  270. package/dist/testKit/mockPackage.d.ts +21 -0
  271. package/dist/testKit/mockPackage.d.ts.map +1 -0
  272. package/dist/testKit/mockPackage.js +91 -0
  273. package/dist/testKit/mockPackage.js.map +1 -0
  274. package/dist/testKit/withConsoleErrors.d.ts +2 -0
  275. package/dist/testKit/withConsoleErrors.d.ts.map +1 -0
  276. package/dist/testKit/withConsoleErrors.js +16 -0
  277. package/dist/testKit/withConsoleErrors.js.map +1 -0
  278. package/dist/testKit/withThrowOnError.d.ts +3 -0
  279. package/dist/testKit/withThrowOnError.d.ts.map +1 -0
  280. package/dist/testKit/withThrowOnError.js +31 -0
  281. package/dist/testKit/withThrowOnError.js.map +1 -0
  282. package/jest.config.js +16 -0
  283. package/package.json +5 -3
  284. package/src/API.ts +474 -378
  285. package/src/IterableWeakMap.ts +121 -0
  286. package/src/appHost.ts +1383 -0
  287. package/src/appHostServices.ts +42 -0
  288. package/src/appHostUtils.ts +11 -0
  289. package/src/extensionSlot.ts +96 -0
  290. package/src/hot.ts +53 -0
  291. package/src/index.ts +55 -3
  292. package/src/installedShellsState.ts +54 -0
  293. package/src/interceptAnyObject.ts +39 -0
  294. package/src/interceptEntryPoints.ts +25 -0
  295. package/src/invokeSlotCallbacks.ts +20 -0
  296. package/src/loggers.ts +112 -0
  297. package/src/monitorAPI.ts +71 -0
  298. package/src/repluggableAppDebug/debug.d.ts +37 -0
  299. package/src/repluggableAppDebug/index.ts +1 -0
  300. package/src/repluggableAppDebug/performanceDebugInfo.ts +96 -0
  301. package/src/repluggableAppDebug/repluggableAppDebug.ts +192 -0
  302. package/src/tarjanGraph.ts +96 -0
  303. package/src/throttledStore.ts +355 -0
  304. package/test/IterableWeakMap.spec.ts +284 -0
  305. package/test/appHost.mock.ts +58 -0
  306. package/test/appHost.spec.ts +1629 -0
  307. package/test/customExtensionSlot.spec.ts +153 -0
  308. package/test/extensionSlot.spec.ts +94 -0
  309. package/test/installedShellsState.spec.ts +39 -0
  310. package/test/interceptAnyObject.spec.ts +217 -0
  311. package/test/interceptEntryPoints.spec.ts +291 -0
  312. package/test/loggers.spec.ts +288 -0
  313. package/test/repluggableAppDebug.spec.ts +118 -0
  314. package/test/testKit.spec.tsx +153 -0
  315. package/testKit/emptyLoggerOptions.ts +16 -0
  316. package/testKit/index.ts +172 -0
  317. package/testKit/mockPackage.ts +99 -0
  318. package/testKit/package.json +3 -0
  319. package/testKit/withConsoleErrors.ts +12 -0
  320. package/testKit/withThrowOnError.ts +34 -0
  321. package/tsconfig.json +11 -1
  322. package/dist/es/API.d.ts.map +0 -1
  323. package/dist/es/API.js +0 -2
  324. package/dist/es/API.js.map +0 -1
  325. package/dist/es/index.d.ts +0 -2
  326. package/dist/es/index.d.ts.map +0 -1
  327. package/dist/es/index.js +0 -2
  328. package/dist/es/index.js.map +0 -1
package/src/appHost.ts ADDED
@@ -0,0 +1,1383 @@
1
+ import { AnyAction, Store } from "redux";
2
+ import {
3
+ AnyEntryPoint,
4
+ AnySlotKey,
5
+ AppHost,
6
+ EntryPoint,
7
+ EntryPointOrPackage,
8
+ EntryPointsInfo,
9
+ ExtensionItem,
10
+ ExtensionSlot,
11
+ Lazy,
12
+ LazyEntryPointDescriptor,
13
+ LazyEntryPointFactory,
14
+ PrivateShell,
15
+ ReactComponentContributor,
16
+ ReducersMapObjectContributor,
17
+ ScopedStore,
18
+ Shell,
19
+ ShellsChangedCallback,
20
+ SlotKey,
21
+ ShellBoundaryAspect,
22
+ MemoizeMissHit,
23
+ AppHostOptions,
24
+ StatisticsMemoization,
25
+ Trace,
26
+ AnyFunction,
27
+ FunctionWithSameArgs,
28
+ ContributeAPIOptions,
29
+ APILayer,
30
+ CustomExtensionSlotHandler,
31
+ CustomExtensionSlot,
32
+ ObservableState,
33
+ PrivateAppHost,
34
+ } from "./API";
35
+ import _ from "lodash";
36
+ import {
37
+ AppHostAPI,
38
+ AppHostServicesProvider,
39
+ createAppHostServicesEntryPoint,
40
+ } from "./appHostServices";
41
+ import {
42
+ AnyExtensionSlot,
43
+ createExtensionSlot,
44
+ createCustomExtensionSlot,
45
+ } from "./extensionSlot";
46
+ import {
47
+ InstalledShellsActions,
48
+ InstalledShellsSelectors,
49
+ ShellToggleSet,
50
+ } from "./installedShellsState";
51
+ import { dependentAPIs, declaredAPIs } from "./appHostUtils";
52
+ import {
53
+ createObservable,
54
+ createThrottledStore,
55
+ PrivateObservableState,
56
+ PrivateThrottledStore,
57
+ StateContribution,
58
+ ThrottledStore,
59
+ updateThrottledStore,
60
+ } from "./throttledStore";
61
+ import { ConsoleHostLogger, createShellLogger } from "./loggers";
62
+ import { monitorAPI } from "./monitorAPI";
63
+ import { getCycle, Graph, Tarjan } from "./tarjanGraph";
64
+ import { setupDebugInfo } from "./repluggableAppDebug";
65
+ import { IterableWeakMap } from "./IterableWeakMap";
66
+
67
+ function isMultiArray<T>(v: T[] | T[][]): v is T[][] {
68
+ return _.every(v, _.isArray);
69
+ }
70
+ function castMultiArray<T>(v: T[] | T[][]): T[][] {
71
+ return isMultiArray(v) ? v : [v];
72
+ }
73
+
74
+ export const makeLazyEntryPoint = (
75
+ name: string,
76
+ factory: LazyEntryPointFactory
77
+ ): LazyEntryPointDescriptor => {
78
+ return {
79
+ name,
80
+ factory,
81
+ };
82
+ };
83
+
84
+ export const mainViewSlotKey: SlotKey<ReactComponentContributor> = {
85
+ name: "mainView",
86
+ };
87
+ export const stateSlotKey: SlotKey<StateContribution> = {
88
+ name: "state",
89
+ };
90
+
91
+ interface MemoizedFunctionData {
92
+ f: Partial<_.MemoizedFunction>;
93
+ shouldClear?(): boolean;
94
+ }
95
+
96
+ const toShellToggleSet = (
97
+ names: string[],
98
+ isInstalled: boolean
99
+ ): ShellToggleSet => {
100
+ return names.reduce<ShellToggleSet>(
101
+ (result: ShellToggleSet, name: string) => {
102
+ result[name] = isInstalled;
103
+ return result;
104
+ },
105
+ {}
106
+ );
107
+ };
108
+
109
+ interface UnreadyEntryPointsStore {
110
+ get(): EntryPoint[];
111
+ set(entryPoints: EntryPoint[]): void;
112
+ }
113
+
114
+ const createUnreadyEntryPointsStore = (): UnreadyEntryPointsStore => {
115
+ let entryPoints: EntryPoint[] = [];
116
+
117
+ return {
118
+ get() {
119
+ return entryPoints;
120
+ },
121
+ set(newEntryPoints: EntryPoint[]) {
122
+ entryPoints = newEntryPoints;
123
+ },
124
+ };
125
+ };
126
+
127
+ interface InternalAPILayer extends APILayer {
128
+ dimension: number;
129
+ }
130
+
131
+ const verifyLayersUniqueness = (layers?: APILayer[] | APILayer[][]) => {
132
+ if (!layers) {
133
+ return;
134
+ }
135
+ const flatLayers = _.flatten(layers);
136
+ const nonUnique = _(flatLayers)
137
+ .countBy(({ name }) => name)
138
+ .pickBy((v) => v > 1)
139
+ .keys()
140
+ .value();
141
+ if (nonUnique.length > 0) {
142
+ throw new Error(
143
+ `Cannot initialize host with non unique layers: ${nonUnique}`
144
+ );
145
+ }
146
+ };
147
+
148
+ export function createAppHost(
149
+ initialEntryPointsOrPackages: EntryPointOrPackage[],
150
+ options: AppHostOptions = { monitoring: {} }
151
+ ): AppHost {
152
+ let store: PrivateThrottledStore | null = null;
153
+ let isInstallingEntryPoints: boolean = false;
154
+ let isStoreSubscribersNotifyInProgress = false;
155
+ let isObserversNotifyInProgress = false;
156
+ let shouldFlushMemoizationSync = false;
157
+ const entryPointsInstallationEndCallbacks: Map<string, () => void> =
158
+ new Map();
159
+
160
+ verifyLayersUniqueness(options.layers);
161
+
162
+ const unReadyEntryPointsStore = createUnreadyEntryPointsStore();
163
+
164
+ const layers: InternalAPILayer[][] = _.map(
165
+ options.layers ? castMultiArray(options.layers) : [],
166
+ (singleDimension, i) =>
167
+ _.map(singleDimension, (layer) => ({ ...layer, dimension: i }))
168
+ );
169
+
170
+ const trace: Trace[] = [];
171
+ const memoizedArr: StatisticsMemoization[] = [];
172
+
173
+ const readyAPIs = new Set<AnySlotKey>();
174
+
175
+ const uniqueShellNames = new Set<string>();
176
+ const extensionSlots = new Map<AnySlotKey, AnyExtensionSlot>();
177
+ const slotKeysByName = new Map<string, AnySlotKey>();
178
+ const addedShells = new Map<string, PrivateShell>();
179
+ const shellInstallers = new WeakMap<PrivateShell, string[]>();
180
+ const lazyShells = new Map<string, LazyEntryPointFactory>();
181
+ const shellsChangedCallbacks = new Map<string, ShellsChangedCallback>();
182
+ const APILayers = new WeakMap<AnySlotKey, APILayer[] | undefined>();
183
+
184
+ const memoizedFunctions: IterableWeakMap<AnyFunction, MemoizedFunctionData> =
185
+ new IterableWeakMap();
186
+ let shouldFlushMemoization = false;
187
+
188
+ const hostAPI: AppHostAPI = {
189
+ getAllEntryPoints: () =>
190
+ [...addedShells.entries()].map(([, { entryPoint }]) => entryPoint),
191
+ getAppHostOptions: () => options,
192
+ };
193
+ const appHostServicesEntryPoint = createAppHostServicesEntryPoint(
194
+ () => hostAPI
195
+ );
196
+ const host: PrivateAppHost & AppHostServicesProvider = {
197
+ getStore,
198
+ getAPI,
199
+ getSlot,
200
+ getAllSlotKeys,
201
+ getAllEntryPoints,
202
+ hasShell,
203
+ isLazyEntryPoint,
204
+ addShells,
205
+ removeShells,
206
+ onShellsChanged,
207
+ removeShellsChangedCallback,
208
+ getAppHostServicesShell: appHostServicesEntryPoint.getAppHostServicesShell,
209
+ log: options.logger ? options.logger : ConsoleHostLogger,
210
+ options,
211
+ executeWhenFree,
212
+ };
213
+
214
+ setupDebugInfo({
215
+ host,
216
+ readyAPIs,
217
+ uniqueShellNames,
218
+ extensionSlots,
219
+ addedShells,
220
+ shellInstallers,
221
+ lazyShells,
222
+
223
+ performance: {
224
+ options,
225
+ trace,
226
+ memoizedArr,
227
+ },
228
+
229
+ getUnreadyEntryPoints: unReadyEntryPointsStore.get,
230
+ getOwnSlotKey,
231
+ getAPI,
232
+ });
233
+
234
+ declareSlot<ReactComponentContributor>(mainViewSlotKey);
235
+ declareSlot<StateContribution>(stateSlotKey);
236
+ addShells([appHostServicesEntryPoint]);
237
+
238
+ const memoize = <T extends AnyFunction>(
239
+ func: T,
240
+ resolver: FunctionWithSameArgs<T>
241
+ ): ((...args: Parameters<T>) => ReturnType<T>) &
242
+ Partial<_.MemoizedFunction> &
243
+ Partial<MemoizeMissHit> => {
244
+ if (options.monitoring.disableMemoization) {
245
+ return func;
246
+ }
247
+ const memoized = _.memoize(func, resolver);
248
+
249
+ if (options.monitoring.debugMemoization) {
250
+ Object.defineProperty(memoized, "name", {
251
+ value: `${func.name}_memoized`,
252
+ writable: false,
253
+ });
254
+ }
255
+
256
+ if (options.monitoring.disableMonitoring) {
257
+ return memoized;
258
+ }
259
+
260
+ const enrichedMemoization = enrichMemoization(memoized);
261
+
262
+ if (options.monitoring.debugMemoization) {
263
+ return (...args: any[]) => {
264
+ const memRes = enrichedMemoization(...args);
265
+ const res = func(...args);
266
+ if (!_.isEqual(memRes, res)) {
267
+ console.log(`Memoization Error`);
268
+ console.log(`Memoization returns:`, memRes);
269
+ console.log(`Original Func returns:`, res);
270
+ console.log(`Original Func:`, func);
271
+ }
272
+ return memRes;
273
+ };
274
+ }
275
+ return enrichedMemoization;
276
+ };
277
+
278
+ function lazyEvaluator<F extends AnyFunction, T extends ReturnType<F>>(
279
+ fn: F
280
+ ): Lazy<T> {
281
+ let _value: T;
282
+ let _resolved: boolean = false;
283
+
284
+ return {
285
+ get: () => {
286
+ if (!_resolved) {
287
+ _value = fn();
288
+ _resolved = true;
289
+ }
290
+
291
+ return _value;
292
+ },
293
+ };
294
+ }
295
+
296
+ // we know that addShells completes synchronously
297
+ addShells(initialEntryPointsOrPackages);
298
+
299
+ return host;
300
+
301
+ //TODO: get rid of LazyEntryPointDescriptor
302
+ function isLazyEntryPointDescriptor(
303
+ value: AnyEntryPoint
304
+ ): value is LazyEntryPointDescriptor {
305
+ return typeof (value as LazyEntryPointDescriptor).factory === "function";
306
+ }
307
+
308
+ function enrichMemoization<
309
+ T extends _.MemoizedFunction & Partial<MemoizeMissHit>
310
+ >(memoized: T): T & MemoizeMissHit {
311
+ const memoizedWithMissHit = _.assign(memoized, {
312
+ miss: 0,
313
+ calls: 0,
314
+ hit: 0,
315
+ printHitMiss: () =>
316
+ console.log(
317
+ `calls: ${memoizedWithMissHit.calls}
318
+ hit: ${memoizedWithMissHit.hit}
319
+ miss: ${memoizedWithMissHit.miss}
320
+ `
321
+ ),
322
+ });
323
+
324
+ const getter = memoizedWithMissHit.cache.get.bind(memoized.cache);
325
+
326
+ memoizedWithMissHit.cache.get = (key: any) => {
327
+ memoizedWithMissHit.calls++;
328
+ memoizedWithMissHit.hit++;
329
+ return getter(key);
330
+ };
331
+
332
+ const setter = memoizedWithMissHit.cache.set.bind(
333
+ memoizedWithMissHit.cache
334
+ );
335
+
336
+ memoizedWithMissHit.cache.set = (key: any, value: any) => {
337
+ memoizedWithMissHit.calls++;
338
+ memoizedWithMissHit.miss++;
339
+ return setter(key, value);
340
+ };
341
+ return memoizedWithMissHit;
342
+ }
343
+
344
+ function getLayerByName(layerName: string): InternalAPILayer {
345
+ const layer = _(layers).flatten().find({ name: layerName });
346
+ if (!layer) {
347
+ throw new Error(`Cannot find layer ${layerName}`);
348
+ }
349
+ return layer;
350
+ }
351
+
352
+ type Dependency =
353
+ | { layer?: InternalAPILayer; apiKey: SlotKey<any> }
354
+ | undefined;
355
+ function validateEntryPointLayer(entryPoint: EntryPoint) {
356
+ if (
357
+ !entryPoint.getDependencyAPIs ||
358
+ !entryPoint.layer ||
359
+ _.isEmpty(layers)
360
+ ) {
361
+ return;
362
+ }
363
+ const highestLevelDependencies: Dependency[] = _.chain(
364
+ entryPoint.getDependencyAPIs()
365
+ )
366
+ .flatMap<Dependency>((apiKey) =>
367
+ apiKey.layer
368
+ ? _(apiKey.layer)
369
+ .castArray()
370
+ .map((l) => ({
371
+ layer: getLayerByName(l),
372
+ apiKey,
373
+ }))
374
+ .value()
375
+ : { apiKey }
376
+ )
377
+ .groupBy((dependency) => dependency?.layer?.dimension)
378
+ .map((dimension) =>
379
+ _.maxBy(dimension, (dependency) =>
380
+ dependency?.layer ? dependency.layer.level : -Infinity
381
+ )
382
+ )
383
+ .value();
384
+
385
+ const currentLayers = _(entryPoint.layer)
386
+ .castArray()
387
+ .map((l) => getLayerByName(l))
388
+ .value();
389
+
390
+ const getCurrentLayerOfSameDimension = (
391
+ layer: InternalAPILayer
392
+ ): InternalAPILayer | undefined => {
393
+ return currentLayers.find(
394
+ (entryPointLayer) => entryPointLayer.dimension === layer.dimension
395
+ );
396
+ };
397
+
398
+ highestLevelDependencies.forEach((highestLevelDependency) => {
399
+ const currentLayer =
400
+ highestLevelDependency?.layer &&
401
+ getCurrentLayerOfSameDimension(highestLevelDependency.layer);
402
+ if (
403
+ highestLevelDependency?.layer &&
404
+ currentLayer &&
405
+ currentLayer.level < highestLevelDependency.layer.level
406
+ ) {
407
+ throw new Error(
408
+ `Entry point ${entryPoint.name} of layer ${
409
+ currentLayer.name
410
+ } cannot depend on API ${slotKeyToName(
411
+ highestLevelDependency.apiKey
412
+ )} of layer ${highestLevelDependency.layer.name}`
413
+ );
414
+ }
415
+ });
416
+ }
417
+
418
+ function validateLayers(entryPoints: AnyEntryPoint[]) {
419
+ _.forEach(entryPoints, (ep) => validateEntryPointLayer(ep));
420
+ }
421
+
422
+ function addShells(
423
+ entryPointsOrPackages: EntryPointOrPackage[]
424
+ ): Promise<void> {
425
+ host.log.log("debug", `Adding ${entryPointsOrPackages.length} packages.`);
426
+
427
+ const entryPoints = _.flatten(entryPointsOrPackages);
428
+ const existingEntryPoints = Object.values(addedShells).map(
429
+ (shell) => shell.entryPoint
430
+ );
431
+ const allEntryPoints = existingEntryPoints.concat(
432
+ unReadyEntryPointsStore.get(),
433
+ entryPoints
434
+ );
435
+
436
+ if (!options.disableLayersValidation) {
437
+ validateLayers(entryPoints);
438
+ }
439
+ validateUniqueShellNames(entryPoints);
440
+ !options.disableCheckCircularDependencies &&
441
+ !options.experimentalCyclicMode &&
442
+ validateCircularDependency(allEntryPoints);
443
+
444
+ const [lazyEntryPointsList, readyEntryPointsList] = _.partition(
445
+ entryPoints,
446
+ isLazyEntryPointDescriptor
447
+ ) as [LazyEntryPointDescriptor[], EntryPoint[]];
448
+
449
+ executeInstallShell(readyEntryPointsList);
450
+ lazyEntryPointsList.forEach(registerLazyEntryPoint);
451
+
452
+ setInstalledShellNames(
453
+ getInstalledShellNames().concat(_.map(lazyEntryPointsList, "name"))
454
+ );
455
+ return Promise.resolve();
456
+ }
457
+
458
+ function isAllAPIDependenciesAreReadyOrPending(
459
+ checkedKey: SlotKey<any>,
460
+ pendingEntryPoints: EntryPoint[],
461
+ passed: SlotKey<any>[] = []
462
+ ): boolean {
463
+ // TODO: Avoid iterating N (cycle length) times for the same cycle
464
+ const declarers = pendingEntryPoints.flatMap((ep) =>
465
+ (ep.declareAPIs?.() || []).map((k) => [k, ep] as const)
466
+ );
467
+ const [, keyDeclarerEntryPoint] =
468
+ declarers.find(([k, ep]) => _.isEqual(k, checkedKey)) || [];
469
+ if (!keyDeclarerEntryPoint) {
470
+ return false;
471
+ }
472
+
473
+ const dependencies =
474
+ keyDeclarerEntryPoint.getDependencyAPIs &&
475
+ keyDeclarerEntryPoint.getDependencyAPIs();
476
+ const uncheckDependencies = _.differenceWith(
477
+ dependencies,
478
+ passed,
479
+ _.isEqual
480
+ );
481
+
482
+ const everyDependenciesReadyOrPending = _.every(
483
+ uncheckDependencies,
484
+ (k) =>
485
+ readyAPIs.has(getOwnSlotKey(k)) ||
486
+ isAllAPIDependenciesAreReadyOrPending(
487
+ k,
488
+ pendingEntryPoints,
489
+ passed.concat(checkedKey)
490
+ )
491
+ );
492
+
493
+ return everyDependenciesReadyOrPending;
494
+ }
495
+
496
+ function onInstallShellsEnd() {
497
+ const callbacks = entryPointsInstallationEndCallbacks.values();
498
+ try {
499
+ for (const callback of callbacks) {
500
+ callback();
501
+ }
502
+ } finally {
503
+ entryPointsInstallationEndCallbacks.clear();
504
+ }
505
+ }
506
+
507
+ function executeInstallShell(entryPoints: EntryPoint[]): void {
508
+ const [readyEntryPoints, currentUnReadyEntryPoints] = _.partition(
509
+ entryPoints,
510
+ (entryPoint) => {
511
+ const dependencies =
512
+ entryPoint.getDependencyAPIs && entryPoint.getDependencyAPIs();
513
+ return _.every(
514
+ dependencies,
515
+ (k) =>
516
+ readyAPIs.has(getOwnSlotKey(k)) ||
517
+ (options.experimentalCyclicMode &&
518
+ isAllAPIDependenciesAreReadyOrPending(k, entryPoints))
519
+ );
520
+ }
521
+ );
522
+
523
+ unReadyEntryPointsStore.set(
524
+ _.union(
525
+ _.difference(unReadyEntryPointsStore.get(), readyEntryPoints),
526
+ currentUnReadyEntryPoints
527
+ )
528
+ );
529
+ if (store && _.isEmpty(readyEntryPoints)) {
530
+ onInstallShellsEnd();
531
+ return;
532
+ }
533
+
534
+ const shells = readyEntryPoints.map(createShell);
535
+ console.log("shells.getAPPHost", shells[0].getAppHost());
536
+ executeReadyEntryPoints(shells);
537
+ }
538
+
539
+ function executeReadyEntryPoints(shells: PrivateShell[]): void {
540
+ isInstallingEntryPoints = true;
541
+ try {
542
+ invokeEntryPointPhase(
543
+ "getDependencyAPIs",
544
+ shells,
545
+ (f) =>
546
+ f.entryPoint.getDependencyAPIs &&
547
+ f.setDependencyAPIs(f.entryPoint.getDependencyAPIs()),
548
+ (f) => !!f.entryPoint.getDependencyAPIs
549
+ );
550
+
551
+ invokeEntryPointPhase(
552
+ "attach",
553
+ shells,
554
+ (f) => f.entryPoint.attach && f.entryPoint.attach(f),
555
+ (f) => !!f.entryPoint.attach
556
+ );
557
+
558
+ buildStore();
559
+ shells.forEach((f) => f.setLifecycleState(true, true, false));
560
+
561
+ invokeEntryPointPhase(
562
+ "extend",
563
+ shells,
564
+ (f) => f.entryPoint.extend && f.entryPoint.extend(f),
565
+ (f) => !!f.entryPoint.extend
566
+ );
567
+
568
+ shells.forEach((f) => {
569
+ addedShells.set(f.entryPoint.name, f);
570
+ f.setLifecycleState(true, true, true);
571
+ });
572
+ } finally {
573
+ isInstallingEntryPoints = false;
574
+ }
575
+ executeInstallShell(unReadyEntryPointsStore.get());
576
+ }
577
+
578
+ function executeShellsChangedCallbacks() {
579
+ shellsChangedCallbacks.forEach((f) =>
580
+ f(
581
+ _.keys(
582
+ InstalledShellsSelectors.getInstalledShellsSet(getStore().getState())
583
+ )
584
+ )
585
+ );
586
+ }
587
+
588
+ function setInstalledShellNames(names: string[]) {
589
+ const updates = toShellToggleSet(names, true);
590
+ getStore().dispatch(InstalledShellsActions.updateInstalledShells(updates));
591
+ executeShellsChangedCallbacks();
592
+ }
593
+
594
+ function setUninstalledShellNames(names: string[]) {
595
+ const updates = toShellToggleSet(names, false);
596
+ getStore().dispatch(InstalledShellsActions.updateInstalledShells(updates));
597
+ executeShellsChangedCallbacks();
598
+ }
599
+
600
+ function onShellsChanged(callback: ShellsChangedCallback) {
601
+ const callbackId = _.uniqueId("shells-changed-callback-");
602
+ shellsChangedCallbacks.set(callbackId, callback);
603
+ return callbackId;
604
+ }
605
+
606
+ function removeShellsChangedCallback(callbackId: string) {
607
+ shellsChangedCallbacks.delete(callbackId);
608
+ }
609
+
610
+ function declareSlot<TItem>(
611
+ key: SlotKey<TItem>,
612
+ declaringShell?: Shell
613
+ ): ExtensionSlot<TItem> {
614
+ const newSlot = registerSlotOrThrow(key, () =>
615
+ createExtensionSlot(key, host, declaringShell)
616
+ );
617
+ return newSlot;
618
+ }
619
+
620
+ function declareCustomSlot<TItem>(
621
+ key: SlotKey<TItem>,
622
+ handler: CustomExtensionSlotHandler<TItem>,
623
+ declaringShell?: Shell
624
+ ): CustomExtensionSlot<TItem> {
625
+ const newSlot = registerSlotOrThrow(key, () =>
626
+ createCustomExtensionSlot(key, handler, host, declaringShell)
627
+ );
628
+ return newSlot;
629
+ }
630
+
631
+ function slotKeyToName<T>(key: SlotKey<T>): string {
632
+ return key.version === undefined
633
+ ? key.name
634
+ : `${key.name}(v${key.version})`;
635
+ }
636
+
637
+ function registerSlotOrThrow<TItem, TSlot extends AnyExtensionSlot>(
638
+ key: SlotKey<TItem>,
639
+ factory: () => TSlot
640
+ ): TSlot {
641
+ const slotName = slotKeyToName(key);
642
+ if (!extensionSlots.has(key) && !slotKeysByName.has(slotName)) {
643
+ const newSlot = factory();
644
+
645
+ extensionSlots.set(key, newSlot);
646
+ slotKeysByName.set(slotName, key);
647
+
648
+ return newSlot;
649
+ }
650
+ throw new Error(`Extension slot with key '${slotName}' already exists.`);
651
+ }
652
+
653
+ function getSlot<TItem>(key: SlotKey<TItem>): ExtensionSlot<TItem> {
654
+ const ownKey = getOwnSlotKey(key);
655
+ const anySlot = extensionSlots.get(ownKey);
656
+
657
+ if (anySlot) {
658
+ return anySlot as ExtensionSlot<TItem>;
659
+ }
660
+ throw new Error(
661
+ `Extension slot with key '${slotKeyToName(key)}' doesn't exist.`
662
+ );
663
+ }
664
+
665
+ function getAPI<TAPI>(key: SlotKey<TAPI>): TAPI {
666
+ const APISlot = getSlot<TAPI>(key);
667
+ const item = APISlot.getSingleItem();
668
+ if (item) {
669
+ return item.contribution;
670
+ }
671
+ throw new Error(`API '${slotKeyToName(key)}' doesn't exist.`);
672
+ }
673
+
674
+ function executeWhenFree(key: string, callback: () => void): void {
675
+ if (isInstallingEntryPoints) {
676
+ entryPointsInstallationEndCallbacks.set(key, callback);
677
+ } else {
678
+ callback();
679
+ }
680
+ }
681
+
682
+ function getStore(): ThrottledStore {
683
+ if (store) {
684
+ return store;
685
+ }
686
+ throw new Error("Store was not yet created");
687
+ }
688
+
689
+ function getAllSlotKeys(): AnySlotKey[] {
690
+ return Array.from(extensionSlots.keys());
691
+ }
692
+
693
+ function getAllEntryPoints(): EntryPointsInfo[] {
694
+ throw new Error("not implemented");
695
+ }
696
+
697
+ function hasShell(name: string): boolean {
698
+ const installedShellsSet = InstalledShellsSelectors.getInstalledShellsSet(
699
+ getStore().getState()
700
+ );
701
+ return installedShellsSet[name] === true;
702
+ }
703
+
704
+ function isLazyEntryPoint(name: string): boolean {
705
+ return lazyShells.has(name);
706
+ }
707
+
708
+ function registerLazyEntryPoint(descriptor: LazyEntryPointDescriptor): void {
709
+ lazyShells.set(descriptor.name, descriptor.factory);
710
+ }
711
+
712
+ function getOwnSlotKey<T>(key: SlotKey<T>): SlotKey<T> {
713
+ if (key.public === true) {
714
+ const ownKey = slotKeysByName.get(slotKeyToName(key));
715
+ if (ownKey && ownKey.public) {
716
+ return ownKey as SlotKey<T>;
717
+ }
718
+ }
719
+ return key;
720
+ }
721
+
722
+ function validateUniqueShellNames(entryPoints: AnyEntryPoint[]): void {
723
+ entryPoints.forEach((f) => validateUniqueShellName(f.name));
724
+ }
725
+
726
+ function validateUniqueShellName(name: string): void {
727
+ if (!uniqueShellNames.has(name)) {
728
+ uniqueShellNames.add(name);
729
+ } else {
730
+ throw new Error(`Shell named '${name}' already exists`);
731
+ }
732
+ }
733
+
734
+ function validateCircularDependency(entryPoints: AnyEntryPoint[]): void {
735
+ const allDeclaredAPIs = new Map<string, AnyEntryPoint>();
736
+ for (const ep of entryPoints) {
737
+ const apis = declaredAPIs(ep);
738
+ for (const api of apis) {
739
+ const existingDeclaration = allDeclaredAPIs.get(api.name);
740
+ if (existingDeclaration) {
741
+ host.log.log(
742
+ "warning",
743
+ `The API: ${api.name} is declared in multiple endpoints: ${existingDeclaration.name} and ${ep.name}`
744
+ );
745
+ } else {
746
+ allDeclaredAPIs.set(api.name, ep);
747
+ }
748
+ }
749
+ }
750
+
751
+ const graph = new Graph();
752
+ entryPoints.forEach((ep) => {
753
+ const declaredApis = declaredAPIs(ep).map((x) => slotKeyToName(x));
754
+ const dependencies = dependentAPIs(ep).map((x) => slotKeyToName(x));
755
+ declaredApis.forEach((d) =>
756
+ dependencies.forEach((y) => graph.addConnection(d, y))
757
+ );
758
+ });
759
+
760
+ const tarjan = new Tarjan(graph);
761
+ const sccs = tarjan.run();
762
+
763
+ for (const scc of sccs) {
764
+ if (scc.length > 1) {
765
+ const dependentGraph: { [key: string]: string[] } = {};
766
+ entryPoints.forEach((ep) => {
767
+ const declaredApis = declaredAPIs(ep).map((child) => child.name);
768
+ const dependencies = dependentAPIs(ep).map((child) => child.name);
769
+ declaredApis.forEach((d) => {
770
+ dependentGraph[d] = dependencies;
771
+ });
772
+ });
773
+
774
+ const circle = getCycle(dependentGraph);
775
+ if (circle) {
776
+ const reversedCircle = circle.reverse();
777
+ host.log.log(
778
+ "error",
779
+ `Circular API dependency found: ${reversedCircle.join(" -> ")}`
780
+ );
781
+ throw new Error(`Circular API dependency found`);
782
+ }
783
+ }
784
+ }
785
+ }
786
+
787
+ function buildStore(): Store {
788
+ const contributedState = getSlot(stateSlotKey);
789
+
790
+ if (store) {
791
+ updateThrottledStore(host, store, contributedState);
792
+ } else {
793
+ store = createThrottledStore(
794
+ host,
795
+ contributedState,
796
+ (notifySubscribersIsRunning) => {
797
+ isStoreSubscribersNotifyInProgress = notifySubscribersIsRunning;
798
+ },
799
+ (notifyObserversIsRunning) => {
800
+ isObserversNotifyInProgress = notifyObserversIsRunning;
801
+ },
802
+ (updateShouldFlushMemoizationSync) => {
803
+ shouldFlushMemoizationSync = updateShouldFlushMemoizationSync;
804
+ }
805
+ );
806
+ store.subscribe(() => {
807
+ if (shouldFlushMemoization) {
808
+ shouldFlushMemoization = false;
809
+ flushMemoizedForState();
810
+ }
811
+ });
812
+ store.syncSubscribe(() => {
813
+ shouldFlushMemoization = true;
814
+ if (
815
+ isStoreSubscribersNotifyInProgress ||
816
+ isObserversNotifyInProgress ||
817
+ shouldFlushMemoizationSync
818
+ ) {
819
+ shouldFlushMemoization = false;
820
+ flushMemoizedForState();
821
+ }
822
+ });
823
+ }
824
+
825
+ return store;
826
+ }
827
+
828
+ function flushMemoizedForState() {
829
+ memoizedFunctions.forEach(({ f, shouldClear }) => {
830
+ if ((shouldClear || _.stubTrue)()) {
831
+ clearCache(f);
832
+ }
833
+ });
834
+ }
835
+
836
+ function clearCache(
837
+ memoizedFunction: Partial<_.MemoizedFunction> & Partial<MemoizeMissHit>
838
+ ) {
839
+ if (memoizedFunction.cache && memoizedFunction.cache.clear) {
840
+ memoizedFunction.cache.clear();
841
+ }
842
+ }
843
+
844
+ function invokeEntryPointPhase(
845
+ phase: keyof EntryPoint, // TODO: Exclude 'name'
846
+ shell: PrivateShell[],
847
+ action: (shell: PrivateShell) => void,
848
+ predicate?: (shell: PrivateShell) => boolean
849
+ ): void {
850
+ host.log.log("debug", `--- ${phase} phase ---`);
851
+
852
+ try {
853
+ shell
854
+ .filter((f) => !predicate || predicate(f))
855
+ .forEach((f) => invokeShell(f, action, phase));
856
+ } catch (err) {
857
+ console.error(`${phase} phase FAILED`, err);
858
+ throw err;
859
+ }
860
+
861
+ host.log.log("debug", `--- End of ${phase} phase ---`);
862
+ }
863
+
864
+ function invokeShell(
865
+ shell: PrivateShell,
866
+ action: (shell: PrivateShell) => void,
867
+ phase: string
868
+ ): void {
869
+ host.log.log("debug", `${phase} : ${shell.entryPoint.name}`);
870
+
871
+ try {
872
+ action(shell);
873
+ } catch (err) {
874
+ host.log.log("error", "AppHost.shellFailed", err, {
875
+ shell: shell.name,
876
+ phase,
877
+ message: `Shell '${shell.name}' FAILED ${phase} phase`,
878
+ error: err,
879
+ });
880
+ throw err;
881
+ }
882
+ }
883
+
884
+ function getAPIContributor<TAPI>(key: SlotKey<TAPI>): Shell | undefined {
885
+ const ownKey = getOwnSlotKey(key);
886
+ return extensionSlots.has(ownKey)
887
+ ? _.get(getSlot<TAPI>(ownKey).getSingleItem(), "shell")
888
+ : undefined;
889
+ }
890
+
891
+ function doesExtensionItemBelongToShells(
892
+ extensionItem: ExtensionItem<any>,
893
+ shellNames: string[]
894
+ ) {
895
+ return (
896
+ _.includes(shellNames, extensionItem.shell.name) ||
897
+ _.some(
898
+ _.invoke(
899
+ (extensionItem.shell as PrivateShell).entryPoint,
900
+ "getDependencyAPIs"
901
+ ),
902
+ (APIKey) =>
903
+ _.includes(shellNames, _.get(getAPIContributor(APIKey), "name"))
904
+ )
905
+ );
906
+ }
907
+
908
+ function discardSlotKey<T>(key: SlotKey<T>) {
909
+ const ownKey = getOwnSlotKey(key);
910
+ readyAPIs.delete(ownKey);
911
+ extensionSlots.delete(ownKey);
912
+ slotKeysByName.delete(slotKeyToName(ownKey));
913
+
914
+ host.log.log("debug", `-- Removed slot keys: ${slotKeyToName(ownKey)} --`);
915
+ }
916
+
917
+ function findDependantShells(entryShell: PrivateShell): PrivateShell[] {
918
+ const cache = new Map<string, PrivateShell[]>();
919
+
920
+ const _findDependantShells = (
921
+ declaringShell: PrivateShell
922
+ ): PrivateShell[] =>
923
+ _([...addedShells.entries()])
924
+ .flatMap(([name, shell]) => {
925
+ const cachedValue = cache.get(name);
926
+ if (cachedValue) {
927
+ return cachedValue;
928
+ }
929
+ const dependencyAPIs = shell.entryPoint?.getDependencyAPIs?.() || [];
930
+ const isDependant = dependencyAPIs.some(
931
+ (key) => getAPIContributor(key)?.name === declaringShell.name
932
+ );
933
+ if (!isDependant) {
934
+ return [];
935
+ }
936
+ const dependencies = [shell, ..._findDependantShells(shell)];
937
+ cache.set(name, dependencies);
938
+ return dependencies;
939
+ })
940
+ .uniqBy("name")
941
+ .value();
942
+
943
+ return _findDependantShells(entryShell);
944
+ }
945
+
946
+ function isShellBeingDependantOnInGroup(
947
+ declaringShell: PrivateShell,
948
+ shells: PrivateShell[]
949
+ ): boolean {
950
+ return !!shells.find((dependantShell) => {
951
+ const dependencyAPIs =
952
+ dependantShell.entryPoint?.getDependencyAPIs?.() || [];
953
+ return dependencyAPIs.find(
954
+ (key) => getAPIContributor(key)?.name === declaringShell.name
955
+ );
956
+ });
957
+ }
958
+
959
+ function executeDetachOnShellReadyForRemoval(
960
+ shellsToBeDetached: PrivateShell[],
961
+ originalRequestedRemovalNames: string[]
962
+ ) {
963
+ invokeEntryPointPhase("detach", shellsToBeDetached, (f) =>
964
+ _.invoke(f.entryPoint, "detach", f)
965
+ );
966
+
967
+ const detachedShellsNames = shellsToBeDetached.map(({ name }) => name);
968
+
969
+ const slotKeysToDiscard = findContributedAPIs(detachedShellsNames).concat(
970
+ findDeclaredSlotKeys(detachedShellsNames)
971
+ );
972
+
973
+ extensionSlots.forEach((extensionSlot) =>
974
+ (extensionSlot as ExtensionSlot<any>).discardBy((extensionItem) =>
975
+ doesExtensionItemBelongToShells(extensionItem, detachedShellsNames)
976
+ )
977
+ );
978
+
979
+ detachedShellsNames.forEach((name) => {
980
+ const isResultOfMissingDependency =
981
+ !originalRequestedRemovalNames.includes(name);
982
+ if (isResultOfMissingDependency) {
983
+ const entryPoint = addedShells.get(name)?.entryPoint;
984
+ entryPoint && unReadyEntryPointsStore.get().push(entryPoint);
985
+ }
986
+ addedShells.delete(name);
987
+ uniqueShellNames.delete(name);
988
+ });
989
+
990
+ slotKeysToDiscard.forEach(discardSlotKey);
991
+
992
+ host.log.log("debug", `Done uninstalling ${detachedShellsNames}`);
993
+ }
994
+
995
+ function executeUninstallShells(names: string[]): void {
996
+ host.log.log("debug", `-- Uninstalling ${names} --`);
997
+
998
+ const shellsCandidatesToBeDetached = _(names)
999
+ .map((name) => addedShells.get(name))
1000
+ .compact()
1001
+ .flatMap<PrivateShell>((shell) => [shell, ...findDependantShells(shell)])
1002
+ .uniqBy("name")
1003
+ .value();
1004
+
1005
+ let queue = shellsCandidatesToBeDetached;
1006
+ while (!_.isEmpty(queue)) {
1007
+ const shellsToBeDetached = queue.filter(
1008
+ (ep) => !isShellBeingDependantOnInGroup(ep, queue)
1009
+ );
1010
+ if (_.isEmpty(shellsToBeDetached)) {
1011
+ throw new Error(
1012
+ `Some shells could not detach: ${queue
1013
+ .map(({ name }) => name)
1014
+ .join()}`
1015
+ );
1016
+ }
1017
+ executeDetachOnShellReadyForRemoval(shellsToBeDetached, names);
1018
+ queue = _.differenceBy(queue, shellsToBeDetached, "name");
1019
+ }
1020
+ }
1021
+
1022
+ function findContributedAPIs(shellNames: string[]) {
1023
+ return [...readyAPIs].filter((APIKey) =>
1024
+ _.includes(shellNames, _.get(getAPIContributor(APIKey), "name"))
1025
+ );
1026
+ }
1027
+
1028
+ function findDeclaredSlotKeys(shellNames: string[]) {
1029
+ const shellNameSet = new Set<string>(shellNames);
1030
+ const result: AnySlotKey[] = [];
1031
+ for (const entry of extensionSlots.entries()) {
1032
+ const { declaringShell } = entry[1];
1033
+ if (declaringShell && shellNameSet.has(declaringShell.name)) {
1034
+ result.push(entry[0]);
1035
+ }
1036
+ }
1037
+ return result;
1038
+ }
1039
+
1040
+ function getInstalledShellNames(): string[] {
1041
+ return [...addedShells].map(([v]) => v);
1042
+ }
1043
+
1044
+ function removeShells(names: string[]): Promise<void> {
1045
+ const shellNames = getInstalledShellNames();
1046
+ executeUninstallShells(names);
1047
+ setUninstalledShellNames(
1048
+ _.difference(shellNames, getInstalledShellNames())
1049
+ );
1050
+
1051
+ return Promise.resolve();
1052
+ }
1053
+
1054
+ function createShell(entryPoint: EntryPoint): PrivateShell {
1055
+ let storeEnabled = false;
1056
+ let APIsEnabled = false;
1057
+ let wasInitCompleted = false;
1058
+ let dependencyAPIs: Set<AnySlotKey> = new Set();
1059
+ let nextObservableId = 1;
1060
+ const boundaryAspects: ShellBoundaryAspect[] = [];
1061
+
1062
+ function isOwnContributedAPI<TAPI>(key: SlotKey<TAPI>): boolean {
1063
+ return getAPIContributor(key) === shell;
1064
+ }
1065
+
1066
+ const shell: PrivateShell = {
1067
+ name: entryPoint.name,
1068
+ entryPoint,
1069
+
1070
+ getSlot<TItem>(key: SlotKey<TItem>): ExtensionSlot<TItem> {
1071
+ const slot = host.getSlot(key);
1072
+ const { declaringShell } = slot;
1073
+ if (!declaringShell || declaringShell !== shell) {
1074
+ throw new Error(
1075
+ `Shell '${shell.name}' is trying to get slot '${slotKeyToName(
1076
+ key
1077
+ )}' that is owned by '${
1078
+ declaringShell ? declaringShell.name : "Host"
1079
+ }'`
1080
+ );
1081
+ }
1082
+ return slot;
1083
+ },
1084
+ getAllSlotKeys: host.getAllSlotKeys,
1085
+ getAllEntryPoints: host.getAllEntryPoints,
1086
+ hasShell: host.hasShell,
1087
+ isLazyEntryPoint: host.isLazyEntryPoint,
1088
+ onShellsChanged: host.onShellsChanged,
1089
+ removeShellsChangedCallback: host.removeShellsChangedCallback,
1090
+
1091
+ declareSlot<TItem>(key: SlotKey<TItem>): ExtensionSlot<TItem> {
1092
+ return declareSlot<TItem>(key, shell);
1093
+ },
1094
+
1095
+ declareCustomSlot<TItem>(
1096
+ key: SlotKey<TItem>,
1097
+ handler: CustomExtensionSlotHandler<TItem>
1098
+ ): CustomExtensionSlot<TItem> {
1099
+ return declareCustomSlot<TItem>(key, handler, shell);
1100
+ },
1101
+
1102
+ setLifecycleState(
1103
+ enableStore: boolean,
1104
+ enableAPIs: boolean,
1105
+ initCompleted: boolean
1106
+ ) {
1107
+ storeEnabled = enableStore;
1108
+ APIsEnabled = enableAPIs;
1109
+ wasInitCompleted = initCompleted;
1110
+ },
1111
+
1112
+ setDependencyAPIs(APIs: AnySlotKey[]): void {
1113
+ dependencyAPIs = new Set(APIs);
1114
+ },
1115
+
1116
+ canUseAPIs(): boolean {
1117
+ return APIsEnabled;
1118
+ },
1119
+
1120
+ canUseStore(): boolean {
1121
+ return storeEnabled;
1122
+ },
1123
+
1124
+ wasInitializationCompleted(): boolean {
1125
+ return wasInitCompleted;
1126
+ },
1127
+
1128
+ runLateInitializer<T>(initializer: () => T): T {
1129
+ const saveWasInitCompleted = wasInitCompleted;
1130
+ try {
1131
+ wasInitCompleted = false;
1132
+ return initializer();
1133
+ } finally {
1134
+ wasInitCompleted = saveWasInitCompleted;
1135
+ }
1136
+ },
1137
+
1138
+ addShells(entryPointsOrPackages: EntryPointOrPackage[]): Promise<void> {
1139
+ const shellNamesToBeinstalled = _.flatten(entryPointsOrPackages).map(
1140
+ (x) => x.name
1141
+ );
1142
+ const shellNamesInstalledByCurrentEntryPoint =
1143
+ shellInstallers.get(shell) || [];
1144
+ shellInstallers.set(shell, [
1145
+ ...shellNamesInstalledByCurrentEntryPoint,
1146
+ ...shellNamesToBeinstalled,
1147
+ ]);
1148
+ return host.addShells(entryPointsOrPackages);
1149
+ },
1150
+
1151
+ removeShells(names: string[]): Promise<void> {
1152
+ const namesInstalledByCurrentEntryPoint =
1153
+ shellInstallers.get(shell) || [];
1154
+ const namesNotInstalledByCurrentEntryPoint = _.difference(
1155
+ names,
1156
+ namesInstalledByCurrentEntryPoint
1157
+ );
1158
+ // TODO: Allow entry point to uninstall its own shell ?
1159
+ if (!_.isEmpty(namesNotInstalledByCurrentEntryPoint)) {
1160
+ throw new Error(
1161
+ `Shell ${entryPoint.name} is trying to uninstall shells: ${names} which is are not installed by entry point ${entryPoint.name} - This is not allowed`
1162
+ );
1163
+ }
1164
+ shellInstallers.set(
1165
+ shell,
1166
+ _.without(namesInstalledByCurrentEntryPoint, ...names)
1167
+ );
1168
+ return host.removeShells(names);
1169
+ },
1170
+
1171
+ getAPI<TAPI>(key: SlotKey<TAPI>): TAPI {
1172
+ if (dependencyAPIs.has(key) || isOwnContributedAPI(key)) {
1173
+ return host.getAPI(key);
1174
+ }
1175
+ throw new Error(
1176
+ `API '${slotKeyToName(
1177
+ key
1178
+ )}' is not declared as dependency by entry point '${
1179
+ entryPoint.name
1180
+ }' (forgot to return it from getDependencyAPIs?)`
1181
+ );
1182
+ },
1183
+
1184
+ contributeAPI<TAPI>(
1185
+ key: SlotKey<TAPI>,
1186
+ factory: () => TAPI,
1187
+ apiOptions?: ContributeAPIOptions<TAPI>
1188
+ ): TAPI {
1189
+ host.log.log("debug", `Contributing API ${slotKeyToName(key)}.`);
1190
+
1191
+ if (!_.includes(_.invoke(entryPoint, "declareAPIs") || [], key)) {
1192
+ throw new Error(
1193
+ `Entry point '${
1194
+ entryPoint.name
1195
+ }' is trying to contribute API '${slotKeyToName(
1196
+ key
1197
+ )}' which it didn't declare`
1198
+ );
1199
+ }
1200
+
1201
+ const areSameLayers = (
1202
+ l1: string | string[] | undefined,
1203
+ l2: string | string[] | undefined
1204
+ ) =>
1205
+ _.isEqual(
1206
+ _(l1).castArray().sort().value(),
1207
+ _(l2).castArray().sort().value()
1208
+ );
1209
+
1210
+ if (
1211
+ !options.disableLayersValidation &&
1212
+ (entryPoint.layer || key.layer) &&
1213
+ !areSameLayers(entryPoint.layer, key.layer)
1214
+ ) {
1215
+ throw new Error(
1216
+ `Cannot contribute API ${slotKeyToName(key)} of layer ${
1217
+ key.layer || "<BLANK>"
1218
+ } from entry point ${entryPoint.name} of layer ${
1219
+ entryPoint.layer || "<BLANK>"
1220
+ }`
1221
+ );
1222
+ }
1223
+
1224
+ const api = factory();
1225
+ const monitoredAPI = monitorAPI(
1226
+ shell,
1227
+ options,
1228
+ normalizeApiName(slotKeyToName(key)),
1229
+ api /*, trace, memoizedArr*/,
1230
+ apiOptions
1231
+ );
1232
+ const apiSlot = declareSlot<TAPI>(key);
1233
+
1234
+ APILayers.set(
1235
+ key,
1236
+ !options.disableLayersValidation && entryPoint.layer
1237
+ ? _(entryPoint.layer)
1238
+ .castArray()
1239
+ .map((l) => getLayerByName(l))
1240
+ .value()
1241
+ : undefined
1242
+ );
1243
+ apiSlot.contribute(shell, monitoredAPI);
1244
+
1245
+ readyAPIs.add(key);
1246
+
1247
+ if (!isInstallingEntryPoints) {
1248
+ const shellNames = _.map(unReadyEntryPointsStore.get(), "name");
1249
+ executeInstallShell(unReadyEntryPointsStore.get());
1250
+ setInstalledShellNames(
1251
+ _.difference(
1252
+ shellNames,
1253
+ _.map(unReadyEntryPointsStore.get(), "name")
1254
+ )
1255
+ );
1256
+ }
1257
+
1258
+ return monitoredAPI;
1259
+ },
1260
+
1261
+ contributeState<TState, TAction extends AnyAction = AnyAction>(
1262
+ contributor: ReducersMapObjectContributor<TState, TAction>
1263
+ ): void {
1264
+ const contribution: StateContribution = {
1265
+ notificationScope: "broadcasting",
1266
+ reducerFactory: contributor,
1267
+ };
1268
+ getSlot(stateSlotKey).contribute(shell, contribution);
1269
+ },
1270
+
1271
+ contributeObservableState<
1272
+ TState,
1273
+ TSelectorAPI,
1274
+ TAction extends AnyAction = AnyAction
1275
+ >(
1276
+ contributor: ReducersMapObjectContributor<TState, TAction>,
1277
+ mapStateToSelectors: (state: TState) => TSelectorAPI
1278
+ ): ObservableState<TSelectorAPI> {
1279
+ const observableUniqueName = `${
1280
+ entryPoint.name
1281
+ }/observable_${nextObservableId++}`;
1282
+ const observable = createObservable(
1283
+ shell,
1284
+ observableUniqueName,
1285
+ mapStateToSelectors
1286
+ );
1287
+ observable.subscribe(shell, () => {
1288
+ flushMemoizedForState();
1289
+ });
1290
+ const protectedObservable: PrivateObservableState<
1291
+ TState,
1292
+ TSelectorAPI
1293
+ > = {
1294
+ subscribe: observable.subscribe,
1295
+ current: (allowUnsafeReading?: boolean) => {
1296
+ if (isStoreSubscribersNotifyInProgress && !allowUnsafeReading) {
1297
+ throw new Error(
1298
+ `Observer created by ${shell.name} current() function: ` +
1299
+ "Should not read observable value during subscribers notify. " +
1300
+ "If you wish to read the value, you component should be observing the value directly " +
1301
+ "(using observeWithShell or connectWithShellAndObserve)"
1302
+ );
1303
+ }
1304
+ return observable.current();
1305
+ },
1306
+ notify: observable.notify,
1307
+ };
1308
+ const contribution: StateContribution = {
1309
+ notificationScope: "observable",
1310
+ reducerFactory: contributor,
1311
+ observable,
1312
+ };
1313
+ getSlot(stateSlotKey).contribute(shell, contribution);
1314
+ return protectedObservable;
1315
+ },
1316
+
1317
+ getStore<TState>(): ScopedStore<TState> {
1318
+ return {
1319
+ dispatch: (
1320
+ host.getStore() as PrivateThrottledStore
1321
+ ).dispatchWithShell(shell),
1322
+ subscribe: host.getStore().subscribe,
1323
+ getState: () => {
1324
+ const entireStoreState = host.getStore().getState();
1325
+ return entireStoreState[shell.name];
1326
+ },
1327
+ flush: host.getStore().flush,
1328
+ hasPendingSubscribers: host.getStore().hasPendingSubscribers,
1329
+ deferSubscriberNotifications:
1330
+ host.getStore().deferSubscriberNotifications,
1331
+ };
1332
+ },
1333
+
1334
+ contributeMainView(
1335
+ fromShell: Shell,
1336
+ contributor: ReactComponentContributor
1337
+ ): void {
1338
+ getSlot(mainViewSlotKey).contribute(fromShell, contributor);
1339
+ },
1340
+
1341
+ contributeBoundaryAspect(component: ShellBoundaryAspect): void {
1342
+ boundaryAspects.push(component);
1343
+ },
1344
+
1345
+ memoizeForState(func, resolver, shouldClear?) {
1346
+ const memoized = memoize(func, resolver);
1347
+ memoizedFunctions.set(
1348
+ memoized,
1349
+ shouldClear ? { f: memoized, shouldClear } : { f: memoized }
1350
+ );
1351
+ return memoized;
1352
+ },
1353
+ flushMemoizedForState,
1354
+ memoize(func, resolver) {
1355
+ return memoize(func, resolver);
1356
+ },
1357
+ clearCache,
1358
+
1359
+ getBoundaryAspects(): ShellBoundaryAspect[] {
1360
+ return boundaryAspects;
1361
+ },
1362
+
1363
+ getHostOptions: () => host.options,
1364
+
1365
+ log: createShellLogger(host, entryPoint),
1366
+
1367
+ getAppHost() {
1368
+ return host;
1369
+ },
1370
+
1371
+ lazyEvaluator,
1372
+ };
1373
+
1374
+ return shell;
1375
+ }
1376
+
1377
+ function normalizeApiName(name: string) {
1378
+ return (
1379
+ name.charAt(0).toLowerCase() +
1380
+ name.substring(1).replace(new RegExp(" ", "g"), "")
1381
+ );
1382
+ }
1383
+ }