@theia/plugin-ext 1.45.0 → 1.46.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 (291) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +9 -4
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js +3 -1
  4. package/lib/common/plugin-api-rpc.js.map +1 -1
  5. package/lib/common/plugin-ext-api-contribution.d.ts +35 -5
  6. package/lib/common/plugin-ext-api-contribution.d.ts.map +1 -1
  7. package/lib/common/plugin-ext-api-contribution.js.map +1 -1
  8. package/lib/common/plugin-protocol.d.ts +5 -2
  9. package/lib/common/plugin-protocol.d.ts.map +1 -1
  10. package/lib/common/plugin-protocol.js +1 -0
  11. package/lib/common/plugin-protocol.js.map +1 -1
  12. package/lib/common/proxy-handler.d.ts +7 -0
  13. package/lib/common/proxy-handler.d.ts.map +1 -1
  14. package/lib/common/proxy-handler.js +5 -1
  15. package/lib/common/proxy-handler.js.map +1 -1
  16. package/lib/common/rpc-protocol.d.ts +10 -0
  17. package/lib/common/rpc-protocol.d.ts.map +1 -1
  18. package/lib/common/rpc-protocol.js +32 -3
  19. package/lib/common/rpc-protocol.js.map +1 -1
  20. package/lib/hosted/browser/hosted-plugin.d.ts +16 -74
  21. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  22. package/lib/hosted/browser/hosted-plugin.js +41 -314
  23. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  24. package/lib/hosted/browser/worker/debug-stub.d.ts +2 -2
  25. package/lib/hosted/browser/worker/debug-stub.d.ts.map +1 -1
  26. package/lib/hosted/browser/worker/debug-stub.js +3 -3
  27. package/lib/hosted/browser/worker/debug-stub.js.map +1 -1
  28. package/lib/hosted/browser/worker/worker-env-ext.d.ts +1 -2
  29. package/lib/hosted/browser/worker/worker-env-ext.d.ts.map +1 -1
  30. package/lib/hosted/browser/worker/worker-env-ext.js +18 -4
  31. package/lib/hosted/browser/worker/worker-env-ext.js.map +1 -1
  32. package/lib/hosted/browser/worker/worker-main.js +20 -32
  33. package/lib/hosted/browser/worker/worker-main.js.map +1 -1
  34. package/lib/hosted/browser/worker/worker-plugin-module.d.ts +5 -0
  35. package/lib/hosted/browser/worker/worker-plugin-module.d.ts.map +1 -0
  36. package/lib/hosted/browser/worker/worker-plugin-module.js +71 -0
  37. package/lib/hosted/browser/worker/worker-plugin-module.js.map +1 -0
  38. package/lib/hosted/common/hosted-plugin.d.ts +97 -0
  39. package/lib/hosted/common/hosted-plugin.d.ts.map +1 -0
  40. package/lib/hosted/common/hosted-plugin.js +408 -0
  41. package/lib/hosted/common/hosted-plugin.js.map +1 -0
  42. package/lib/hosted/node/hosted-plugin-process.d.ts +1 -1
  43. package/lib/hosted/node/hosted-plugin-process.d.ts.map +1 -1
  44. package/lib/hosted/node/hosted-plugin-process.js +2 -2
  45. package/lib/hosted/node/hosted-plugin-process.js.map +1 -1
  46. package/lib/hosted/node/plugin-ext-hosted-backend-module.d.ts.map +1 -1
  47. package/lib/hosted/node/plugin-ext-hosted-backend-module.js +2 -0
  48. package/lib/hosted/node/plugin-ext-hosted-backend-module.js.map +1 -1
  49. package/lib/hosted/node/plugin-host-module.d.ts +5 -0
  50. package/lib/hosted/node/plugin-host-module.d.ts.map +1 -0
  51. package/lib/hosted/node/plugin-host-module.js +68 -0
  52. package/lib/hosted/node/plugin-host-module.js.map +1 -0
  53. package/lib/hosted/node/plugin-host-rpc.d.ts +93 -7
  54. package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
  55. package/lib/hosted/node/plugin-host-rpc.js +202 -53
  56. package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
  57. package/lib/hosted/node/plugin-host.js +6 -5
  58. package/lib/hosted/node/plugin-host.js.map +1 -1
  59. package/lib/hosted/node/plugin-reader.d.ts.map +1 -1
  60. package/lib/hosted/node/plugin-reader.js +3 -0
  61. package/lib/hosted/node/plugin-reader.js.map +1 -1
  62. package/lib/hosted/node/plugin-service.d.ts +8 -0
  63. package/lib/hosted/node/plugin-service.d.ts.map +1 -1
  64. package/lib/hosted/node/plugin-service.js +14 -4
  65. package/lib/hosted/node/plugin-service.js.map +1 -1
  66. package/lib/hosted/node/scanners/file-plugin-uri-factory.js +1 -1
  67. package/lib/hosted/node/scanners/file-plugin-uri-factory.js.map +1 -1
  68. package/lib/hosted/node/scanners/scanner-theia.d.ts +17 -3
  69. package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
  70. package/lib/hosted/node/scanners/scanner-theia.js +48 -19
  71. package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
  72. package/lib/main/browser/authentication-main.d.ts.map +1 -1
  73. package/lib/main/browser/authentication-main.js +3 -1
  74. package/lib/main/browser/authentication-main.js.map +1 -1
  75. package/lib/main/browser/env-main.d.ts +1 -10
  76. package/lib/main/browser/env-main.d.ts.map +1 -1
  77. package/lib/main/browser/env-main.js +2 -21
  78. package/lib/main/browser/env-main.js.map +1 -1
  79. package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
  80. package/lib/main/browser/menus/menus-contribution-handler.js +6 -3
  81. package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
  82. package/lib/main/browser/menus/plugin-menu-command-adapter.js +1 -1
  83. package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
  84. package/lib/main/browser/message-registry-main.d.ts +6 -4
  85. package/lib/main/browser/message-registry-main.d.ts.map +1 -1
  86. package/lib/main/browser/message-registry-main.js +7 -19
  87. package/lib/main/browser/message-registry-main.js.map +1 -1
  88. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts +1 -0
  89. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts.map +1 -1
  90. package/lib/main/browser/notebooks/renderers/cell-output-webview.js +23 -22
  91. package/lib/main/browser/notebooks/renderers/cell-output-webview.js.map +1 -1
  92. package/lib/main/browser/notebooks/renderers/output-webview-internal.d.ts.map +1 -1
  93. package/lib/main/browser/notebooks/renderers/output-webview-internal.js +22 -14
  94. package/lib/main/browser/notebooks/renderers/output-webview-internal.js.map +1 -1
  95. package/lib/main/browser/notebooks/renderers/webview-communication.d.ts +2 -1
  96. package/lib/main/browser/notebooks/renderers/webview-communication.d.ts.map +1 -1
  97. package/lib/main/browser/notification-main.d.ts +2 -14
  98. package/lib/main/browser/notification-main.d.ts.map +1 -1
  99. package/lib/main/browser/notification-main.js +3 -52
  100. package/lib/main/browser/notification-main.js.map +1 -1
  101. package/lib/main/browser/terminal-main.d.ts +1 -1
  102. package/lib/main/browser/terminal-main.d.ts.map +1 -1
  103. package/lib/main/browser/terminal-main.js +2 -2
  104. package/lib/main/browser/terminal-main.js.map +1 -1
  105. package/lib/main/browser/view/plugin-view-registry.d.ts.map +1 -1
  106. package/lib/main/browser/view/plugin-view-registry.js +5 -2
  107. package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
  108. package/lib/main/browser/webview/webview-context-keys.d.ts +5 -1
  109. package/lib/main/browser/webview/webview-context-keys.d.ts.map +1 -1
  110. package/lib/main/browser/webview/webview-context-keys.js +13 -4
  111. package/lib/main/browser/webview/webview-context-keys.js.map +1 -1
  112. package/lib/main/browser/webview/webview-widget-factory.d.ts.map +1 -1
  113. package/lib/main/browser/webview/webview-widget-factory.js +2 -1
  114. package/lib/main/browser/webview/webview-widget-factory.js.map +1 -1
  115. package/lib/main/browser/webview/webview.d.ts +1 -0
  116. package/lib/main/browser/webview/webview.d.ts.map +1 -1
  117. package/lib/main/browser/webview/webview.js +1 -0
  118. package/lib/main/browser/webview/webview.js.map +1 -1
  119. package/lib/main/browser/webviews-main.d.ts.map +1 -1
  120. package/lib/main/browser/webviews-main.js +7 -2
  121. package/lib/main/browser/webviews-main.js.map +1 -1
  122. package/lib/main/common/basic-message-registry-main.d.ts +14 -0
  123. package/lib/main/common/basic-message-registry-main.d.ts.map +1 -0
  124. package/lib/main/common/basic-message-registry-main.js +50 -0
  125. package/lib/main/common/basic-message-registry-main.js.map +1 -0
  126. package/lib/main/common/basic-notification-main.d.ts +19 -0
  127. package/lib/main/common/basic-notification-main.d.ts.map +1 -0
  128. package/lib/main/common/basic-notification-main.js +75 -0
  129. package/lib/main/common/basic-notification-main.js.map +1 -0
  130. package/lib/main/common/env-main.d.ts +11 -0
  131. package/lib/main/common/env-main.d.ts.map +1 -0
  132. package/lib/main/common/env-main.js +40 -0
  133. package/lib/main/common/env-main.js.map +1 -0
  134. package/lib/main/node/handlers/plugin-theia-directory-handler.d.ts +8 -3
  135. package/lib/main/node/handlers/plugin-theia-directory-handler.d.ts.map +1 -1
  136. package/lib/main/node/handlers/plugin-theia-directory-handler.js +38 -20
  137. package/lib/main/node/handlers/plugin-theia-directory-handler.js.map +1 -1
  138. package/lib/main/node/handlers/plugin-theia-file-handler.js +1 -1
  139. package/lib/main/node/handlers/plugin-theia-file-handler.js.map +1 -1
  140. package/lib/main/node/plugin-deployer-impl.d.ts.map +1 -1
  141. package/lib/main/node/plugin-deployer-impl.js +5 -1
  142. package/lib/main/node/plugin-deployer-impl.js.map +1 -1
  143. package/lib/main/node/plugins-key-value-storage.js +1 -1
  144. package/lib/main/node/plugins-key-value-storage.js.map +1 -1
  145. package/lib/plugin/clipboard-ext.d.ts +3 -2
  146. package/lib/plugin/clipboard-ext.d.ts.map +1 -1
  147. package/lib/plugin/clipboard-ext.js +28 -4
  148. package/lib/plugin/clipboard-ext.js.map +1 -1
  149. package/lib/plugin/debug/debug-ext.d.ts +3 -1
  150. package/lib/plugin/debug/debug-ext.d.ts.map +1 -1
  151. package/lib/plugin/debug/debug-ext.js +31 -4
  152. package/lib/plugin/debug/debug-ext.js.map +1 -1
  153. package/lib/plugin/documents.js +2 -2
  154. package/lib/plugin/documents.js.map +1 -1
  155. package/lib/plugin/editors-and-documents.d.ts +1 -2
  156. package/lib/plugin/editors-and-documents.d.ts.map +1 -1
  157. package/lib/plugin/editors-and-documents.js +21 -4
  158. package/lib/plugin/editors-and-documents.js.map +1 -1
  159. package/lib/plugin/env.d.ts +6 -2
  160. package/lib/plugin/env.d.ts.map +1 -1
  161. package/lib/plugin/env.js +37 -4
  162. package/lib/plugin/env.js.map +1 -1
  163. package/lib/plugin/localization-ext.d.ts +3 -2
  164. package/lib/plugin/localization-ext.d.ts.map +1 -1
  165. package/lib/plugin/localization-ext.js +30 -4
  166. package/lib/plugin/localization-ext.js.map +1 -1
  167. package/lib/plugin/message-registry.d.ts +2 -1
  168. package/lib/plugin/message-registry.d.ts.map +1 -1
  169. package/lib/plugin/message-registry.js +28 -4
  170. package/lib/plugin/message-registry.js.map +1 -1
  171. package/lib/plugin/node/debug/debug.spec.js +21 -1
  172. package/lib/plugin/node/debug/debug.spec.js.map +1 -1
  173. package/lib/plugin/node/env-node-ext.d.ts +1 -6
  174. package/lib/plugin/node/env-node-ext.d.ts.map +1 -1
  175. package/lib/plugin/node/env-node-ext.js +18 -10
  176. package/lib/plugin/node/env-node-ext.js.map +1 -1
  177. package/lib/plugin/node/plugin-container-module.d.ts +75 -0
  178. package/lib/plugin/node/plugin-container-module.d.ts.map +1 -0
  179. package/lib/plugin/node/plugin-container-module.js +115 -0
  180. package/lib/plugin/node/plugin-container-module.js.map +1 -0
  181. package/lib/plugin/notebook/notebook-kernels.d.ts.map +1 -1
  182. package/lib/plugin/notebook/notebook-kernels.js +0 -1
  183. package/lib/plugin/notebook/notebook-kernels.js.map +1 -1
  184. package/lib/plugin/plugin-context.d.ts.map +1 -1
  185. package/lib/plugin/plugin-context.js +9 -1
  186. package/lib/plugin/plugin-context.js.map +1 -1
  187. package/lib/plugin/plugin-manager.d.ts +26 -17
  188. package/lib/plugin/plugin-manager.d.ts.map +1 -1
  189. package/lib/plugin/plugin-manager.js +107 -37
  190. package/lib/plugin/plugin-manager.js.map +1 -1
  191. package/lib/plugin/plugin-storage.d.ts +11 -3
  192. package/lib/plugin/plugin-storage.d.ts.map +1 -1
  193. package/lib/plugin/plugin-storage.js +25 -5
  194. package/lib/plugin/plugin-storage.js.map +1 -1
  195. package/lib/plugin/preference-registry.d.ts +3 -2
  196. package/lib/plugin/preference-registry.d.ts.map +1 -1
  197. package/lib/plugin/preference-registry.js +35 -5
  198. package/lib/plugin/preference-registry.js.map +1 -1
  199. package/lib/plugin/preference-registry.spec.js +8 -1
  200. package/lib/plugin/preference-registry.spec.js.map +1 -1
  201. package/lib/plugin/quick-open.js +3 -3
  202. package/lib/plugin/quick-open.js.map +1 -1
  203. package/lib/plugin/secrets-ext.d.ts +16 -7
  204. package/lib/plugin/secrets-ext.d.ts.map +1 -1
  205. package/lib/plugin/secrets-ext.js +23 -3
  206. package/lib/plugin/secrets-ext.js.map +1 -1
  207. package/lib/plugin/terminal-ext.d.ts +1 -1
  208. package/lib/plugin/terminal-ext.d.ts.map +1 -1
  209. package/lib/plugin/terminal-ext.js +26 -6
  210. package/lib/plugin/terminal-ext.js.map +1 -1
  211. package/lib/plugin/types-impl.d.ts +22 -2
  212. package/lib/plugin/types-impl.d.ts.map +1 -1
  213. package/lib/plugin/types-impl.js +22 -6
  214. package/lib/plugin/types-impl.js.map +1 -1
  215. package/lib/plugin/webview-views.d.ts.map +1 -1
  216. package/lib/plugin/webview-views.js +2 -1
  217. package/lib/plugin/webview-views.js.map +1 -1
  218. package/lib/plugin/webviews.d.ts +7 -5
  219. package/lib/plugin/webviews.d.ts.map +1 -1
  220. package/lib/plugin/webviews.js +46 -12
  221. package/lib/plugin/webviews.js.map +1 -1
  222. package/lib/plugin/workspace.d.ts +4 -3
  223. package/lib/plugin/workspace.d.ts.map +1 -1
  224. package/lib/plugin/workspace.js +40 -6
  225. package/lib/plugin/workspace.js.map +1 -1
  226. package/package.json +29 -29
  227. package/src/common/plugin-api-rpc.ts +10 -6
  228. package/src/common/plugin-ext-api-contribution.ts +38 -5
  229. package/src/common/plugin-protocol.ts +7 -2
  230. package/src/common/proxy-handler.ts +14 -1
  231. package/src/common/rpc-protocol.ts +41 -3
  232. package/src/hosted/browser/hosted-plugin.ts +47 -337
  233. package/src/hosted/browser/worker/debug-stub.ts +4 -3
  234. package/src/hosted/browser/worker/worker-env-ext.ts +5 -4
  235. package/src/hosted/browser/worker/worker-main.ts +103 -115
  236. package/src/hosted/browser/worker/worker-plugin-module.ts +73 -0
  237. package/src/hosted/common/hosted-plugin.ts +456 -0
  238. package/src/hosted/node/hosted-plugin-process.ts +4 -4
  239. package/src/hosted/node/plugin-ext-hosted-backend-module.ts +3 -1
  240. package/src/hosted/node/plugin-host-module.ts +69 -0
  241. package/src/hosted/node/plugin-host-rpc.ts +232 -73
  242. package/src/hosted/node/plugin-host.ts +9 -7
  243. package/src/hosted/node/plugin-reader.ts +3 -0
  244. package/src/hosted/node/plugin-service.ts +21 -4
  245. package/src/hosted/node/scanners/file-plugin-uri-factory.ts +1 -1
  246. package/src/hosted/node/scanners/scanner-theia.ts +46 -12
  247. package/src/main/browser/authentication-main.ts +3 -1
  248. package/src/main/browser/env-main.ts +1 -28
  249. package/src/main/browser/menus/menus-contribution-handler.ts +8 -3
  250. package/src/main/browser/menus/plugin-menu-command-adapter.ts +1 -1
  251. package/src/main/browser/message-registry-main.ts +10 -23
  252. package/src/main/browser/notebooks/renderers/cell-output-webview.tsx +26 -24
  253. package/src/main/browser/notebooks/renderers/output-webview-internal.ts +22 -13
  254. package/src/main/browser/notebooks/renderers/webview-communication.ts +2 -1
  255. package/src/main/browser/notification-main.ts +4 -64
  256. package/src/main/browser/terminal-main.ts +2 -2
  257. package/src/main/browser/view/plugin-view-registry.ts +6 -3
  258. package/src/main/browser/webview/webview-context-keys.ts +17 -4
  259. package/src/main/browser/webview/webview-widget-factory.ts +2 -1
  260. package/src/main/browser/webview/webview.ts +2 -0
  261. package/src/main/browser/webviews-main.ts +7 -2
  262. package/src/main/common/basic-message-registry-main.ts +53 -0
  263. package/src/main/common/basic-notification-main.ts +86 -0
  264. package/src/main/common/env-main.ts +44 -0
  265. package/src/main/node/handlers/plugin-theia-directory-handler.ts +38 -16
  266. package/src/main/node/handlers/plugin-theia-file-handler.ts +1 -1
  267. package/src/main/node/plugin-deployer-impl.ts +5 -1
  268. package/src/main/node/plugins-key-value-storage.ts +1 -1
  269. package/src/plugin/clipboard-ext.ts +9 -3
  270. package/src/plugin/debug/debug-ext.ts +11 -2
  271. package/src/plugin/documents.ts +2 -2
  272. package/src/plugin/editors-and-documents.ts +5 -3
  273. package/src/plugin/env.ts +19 -3
  274. package/src/plugin/localization-ext.ts +8 -3
  275. package/src/plugin/message-registry.ts +7 -2
  276. package/src/plugin/node/debug/debug.spec.ts +5 -1
  277. package/src/plugin/node/env-node-ext.ts +5 -10
  278. package/src/plugin/node/plugin-container-module.ts +165 -0
  279. package/src/plugin/notebook/notebook-kernels.ts +0 -1
  280. package/src/plugin/plugin-context.ts +11 -2
  281. package/src/plugin/plugin-manager.ts +99 -45
  282. package/src/plugin/plugin-storage.ts +22 -4
  283. package/src/plugin/preference-registry.spec.ts +6 -1
  284. package/src/plugin/preference-registry.ts +11 -5
  285. package/src/plugin/quick-open.ts +3 -3
  286. package/src/plugin/secrets-ext.ts +25 -5
  287. package/src/plugin/terminal-ext.ts +5 -3
  288. package/src/plugin/types-impl.ts +30 -2
  289. package/src/plugin/webview-views.ts +2 -1
  290. package/src/plugin/webviews.ts +22 -13
  291. package/src/plugin/workspace.ts +14 -4
@@ -0,0 +1,456 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 Red Hat, Inc. and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /*---------------------------------------------------------------------------------------------
17
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+ // some code copied and modified from https://github.com/microsoft/vscode/blob/da5fb7d5b865aa522abc7e82c10b746834b98639/src/vs/workbench/api/node/extHostExtensionService.ts
21
+
22
+ /* eslint-disable @typescript-eslint/no-explicit-any */
23
+
24
+ import debounce = require('@theia/core/shared/lodash.debounce');
25
+ import { injectable, inject, interfaces, named, postConstruct } from '@theia/core/shared/inversify';
26
+ import { PluginMetadata, HostedPluginServer, DeployedPlugin, PluginServer, PluginIdentifiers } from '../../common/plugin-protocol';
27
+ import { AbstractPluginManagerExt, ConfigStorage } from '../../common/plugin-api-rpc';
28
+ import {
29
+ Disposable, DisposableCollection, Emitter,
30
+ ILogger, ContributionProvider,
31
+ RpcProxy
32
+ } from '@theia/core';
33
+ import { MainPluginApiProvider } from '../../common/plugin-ext-api-contribution';
34
+ import { PluginPathsService } from '../../main/common/plugin-paths-protocol';
35
+ import { Deferred } from '@theia/core/lib/common/promise-util';
36
+ import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
37
+ import { environment } from '@theia/core/shared/@theia/application-package/lib/environment';
38
+ import { Measurement, Stopwatch } from '@theia/core/lib/common';
39
+
40
+ export type PluginHost = 'frontend' | string;
41
+
42
+ export const ALL_ACTIVATION_EVENT = '*';
43
+
44
+ export function isConnectionScopedBackendPlugin(plugin: DeployedPlugin): boolean {
45
+ const entryPoint = plugin.metadata.model.entryPoint;
46
+
47
+ // A plugin doesn't have to have any entry-point if it doesn't need the activation handler,
48
+ // in which case it's assumed to be a backend plugin.
49
+ return !entryPoint.headless || !!entryPoint.backend;
50
+ }
51
+
52
+ @injectable()
53
+ export abstract class AbstractHostedPluginSupport<PM extends AbstractPluginManagerExt<any>, HPS extends HostedPluginServer | RpcProxy<HostedPluginServer>> {
54
+
55
+ protected container: interfaces.Container;
56
+
57
+ @inject(ILogger)
58
+ protected readonly logger: ILogger;
59
+
60
+ @inject(HostedPluginServer)
61
+ protected readonly server: HPS;
62
+
63
+ @inject(ContributionProvider)
64
+ @named(MainPluginApiProvider)
65
+ protected readonly mainPluginApiProviders: ContributionProvider<MainPluginApiProvider>;
66
+
67
+ @inject(PluginServer)
68
+ protected readonly pluginServer: PluginServer;
69
+
70
+ @inject(PluginPathsService)
71
+ protected readonly pluginPathsService: PluginPathsService;
72
+
73
+ @inject(EnvVariablesServer)
74
+ protected readonly envServer: EnvVariablesServer;
75
+
76
+ @inject(Stopwatch)
77
+ protected readonly stopwatch: Stopwatch;
78
+
79
+ protected theiaReadyPromise: Promise<unknown>;
80
+
81
+ protected readonly managers = new Map<string, PM>();
82
+
83
+ protected readonly contributions = new Map<PluginIdentifiers.UnversionedId, PluginContributions>();
84
+
85
+ protected readonly activationEvents = new Set<string>();
86
+
87
+ protected readonly onDidChangePluginsEmitter = new Emitter<void>();
88
+ readonly onDidChangePlugins = this.onDidChangePluginsEmitter.event;
89
+
90
+ protected readonly deferredWillStart = new Deferred<void>();
91
+ /**
92
+ * Resolves when the initial plugins are loaded and about to be started.
93
+ */
94
+ get willStart(): Promise<void> {
95
+ return this.deferredWillStart.promise;
96
+ }
97
+
98
+ protected readonly deferredDidStart = new Deferred<void>();
99
+ /**
100
+ * Resolves when the initial plugins are started.
101
+ */
102
+ get didStart(): Promise<void> {
103
+ return this.deferredDidStart.promise;
104
+ }
105
+
106
+ constructor(protected readonly clientId: string) { }
107
+
108
+ @postConstruct()
109
+ protected init(): void {
110
+ this.theiaReadyPromise = this.createTheiaReadyPromise();
111
+ }
112
+
113
+ protected abstract createTheiaReadyPromise(): Promise<unknown>;
114
+
115
+ get plugins(): PluginMetadata[] {
116
+ const plugins: PluginMetadata[] = [];
117
+ this.contributions.forEach(contributions => plugins.push(contributions.plugin.metadata));
118
+ return plugins;
119
+ }
120
+
121
+ getPlugin(id: PluginIdentifiers.UnversionedId): DeployedPlugin | undefined {
122
+ const contributions = this.contributions.get(id);
123
+ return contributions && contributions.plugin;
124
+ }
125
+
126
+ /** do not call it, except from the plugin frontend contribution */
127
+ onStart(container: interfaces.Container): void {
128
+ this.container = container;
129
+ this.load();
130
+ this.afterStart();
131
+ }
132
+
133
+ protected afterStart(): void {
134
+ // Nothing to do in the abstract
135
+ }
136
+
137
+ protected loadQueue: Promise<void> = Promise.resolve(undefined);
138
+ load = debounce(() => this.loadQueue = this.loadQueue.then(async () => {
139
+ try {
140
+ await this.runOperation(() => this.doLoad());
141
+ } catch (e) {
142
+ console.error('Failed to load plugins:', e);
143
+ }
144
+ }), 50, { leading: true });
145
+
146
+ protected runOperation(operation: () => Promise<void>): Promise<void> {
147
+ return operation();
148
+ }
149
+
150
+ protected async doLoad(): Promise<void> {
151
+ const toDisconnect = new DisposableCollection(Disposable.create(() => { /* mark as connected */ }));
152
+
153
+ await this.beforeSyncPlugins(toDisconnect);
154
+
155
+ // process empty plugins as well in order to properly remove stale plugin widgets
156
+ await this.syncPlugins();
157
+
158
+ // it has to be resolved before awaiting layout is initialized
159
+ // otherwise clients can hang forever in the initialization phase
160
+ this.deferredWillStart.resolve();
161
+
162
+ await this.beforeLoadContributions(toDisconnect);
163
+
164
+ if (toDisconnect.disposed) {
165
+ // if disconnected then don't try to load plugin contributions
166
+ return;
167
+ }
168
+ const contributionsByHost = this.loadContributions(toDisconnect);
169
+
170
+ await this.afterLoadContributions(toDisconnect);
171
+
172
+ await this.theiaReadyPromise;
173
+ if (toDisconnect.disposed) {
174
+ // if disconnected then don't try to init plugin code and dynamic contributions
175
+ return;
176
+ }
177
+ await this.startPlugins(contributionsByHost, toDisconnect);
178
+
179
+ this.deferredDidStart.resolve();
180
+ }
181
+
182
+ protected beforeSyncPlugins(toDisconnect: DisposableCollection): Promise<void> {
183
+ // Nothing to do in the abstract
184
+ return Promise.resolve();
185
+ }
186
+
187
+ protected beforeLoadContributions(toDisconnect: DisposableCollection): Promise<void> {
188
+ // Nothing to do in the abstract
189
+ return Promise.resolve();
190
+ }
191
+
192
+ protected afterLoadContributions(toDisconnect: DisposableCollection): Promise<void> {
193
+ // Nothing to do in the abstract
194
+ return Promise.resolve();
195
+ }
196
+
197
+ /**
198
+ * Sync loaded and deployed plugins:
199
+ * - undeployed plugins are unloaded
200
+ * - newly deployed plugins are initialized
201
+ */
202
+ protected async syncPlugins(): Promise<void> {
203
+ let initialized = 0;
204
+ const waitPluginsMeasurement = this.measure('waitForDeployment');
205
+ let syncPluginsMeasurement: Measurement | undefined;
206
+
207
+ const toUnload = new Set(this.contributions.keys());
208
+ let didChangeInstallationStatus = false;
209
+ try {
210
+ const newPluginIds: PluginIdentifiers.VersionedId[] = [];
211
+ const [deployedPluginIds, uninstalledPluginIds] = await Promise.all([this.server.getDeployedPluginIds(), this.server.getUninstalledPluginIds()]);
212
+ waitPluginsMeasurement.log('Waiting for backend deployment');
213
+ syncPluginsMeasurement = this.measure('syncPlugins');
214
+ for (const versionedId of deployedPluginIds) {
215
+ const unversionedId = PluginIdentifiers.unversionedFromVersioned(versionedId);
216
+ toUnload.delete(unversionedId);
217
+ if (!this.contributions.has(unversionedId)) {
218
+ newPluginIds.push(versionedId);
219
+ }
220
+ }
221
+ for (const pluginId of toUnload) {
222
+ this.contributions.get(pluginId)?.dispose();
223
+ }
224
+ for (const versionedId of uninstalledPluginIds) {
225
+ const plugin = this.getPlugin(PluginIdentifiers.unversionedFromVersioned(versionedId));
226
+ if (plugin && PluginIdentifiers.componentsToVersionedId(plugin.metadata.model) === versionedId && !plugin.metadata.outOfSync) {
227
+ plugin.metadata.outOfSync = didChangeInstallationStatus = true;
228
+ }
229
+ }
230
+ for (const contribution of this.contributions.values()) {
231
+ if (contribution.plugin.metadata.outOfSync && !uninstalledPluginIds.includes(PluginIdentifiers.componentsToVersionedId(contribution.plugin.metadata.model))) {
232
+ contribution.plugin.metadata.outOfSync = false;
233
+ didChangeInstallationStatus = true;
234
+ }
235
+ }
236
+ if (newPluginIds.length) {
237
+ const deployedPlugins = await this.server.getDeployedPlugins({ pluginIds: newPluginIds });
238
+
239
+ const plugins: DeployedPlugin[] = [];
240
+ for (const plugin of deployedPlugins) {
241
+ const accepted = this.acceptPlugin(plugin);
242
+ if (typeof accepted === 'object') {
243
+ plugins.push(accepted);
244
+ } else if (accepted) {
245
+ plugins.push(plugin);
246
+ }
247
+ }
248
+
249
+ for (const plugin of plugins) {
250
+ const pluginId = PluginIdentifiers.componentsToUnversionedId(plugin.metadata.model);
251
+ const contributions = new PluginContributions(plugin);
252
+ this.contributions.set(pluginId, contributions);
253
+ contributions.push(Disposable.create(() => this.contributions.delete(pluginId)));
254
+ initialized++;
255
+ }
256
+ }
257
+ } finally {
258
+ if (initialized || toUnload.size || didChangeInstallationStatus) {
259
+ this.onDidChangePluginsEmitter.fire(undefined);
260
+ }
261
+
262
+ if (!syncPluginsMeasurement) {
263
+ // await didn't complete normally
264
+ waitPluginsMeasurement.error('Backend deployment failed.');
265
+ }
266
+ }
267
+ if (initialized > 0) {
268
+ // Only log sync measurement if there are were plugins to sync.
269
+ syncPluginsMeasurement?.log(`Sync of ${this.getPluginCount(initialized)}`);
270
+ } else {
271
+ syncPluginsMeasurement?.stop();
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Accept a deployed plugin to load in this host, or reject it, or adapt it for loading.
277
+ * The result may be a boolean to accept (`true`) or reject (`false`) the plugin as is,
278
+ * or else an adaptation of the original `plugin` to load in its stead.
279
+ */
280
+ protected abstract acceptPlugin(plugin: DeployedPlugin): boolean | DeployedPlugin;
281
+
282
+ /**
283
+ * Always synchronous in order to simplify handling disconnections.
284
+ * @throws never
285
+ */
286
+ protected loadContributions(toDisconnect: DisposableCollection): Map<PluginHost, PluginContributions[]> {
287
+ let loaded = 0;
288
+ const loadPluginsMeasurement = this.measure('loadPlugins');
289
+
290
+ const hostContributions = new Map<PluginHost, PluginContributions[]>();
291
+ console.log(`[${this.clientId}] Loading plugin contributions`);
292
+ for (const contributions of this.contributions.values()) {
293
+ const plugin = contributions.plugin.metadata;
294
+ const pluginId = plugin.model.id;
295
+
296
+ if (contributions.state === PluginContributions.State.INITIALIZING) {
297
+ contributions.state = PluginContributions.State.LOADING;
298
+ contributions.push(Disposable.create(() => console.log(`[${pluginId}]: Unloaded plugin.`)));
299
+ contributions.push(this.handleContributions(contributions.plugin));
300
+ contributions.state = PluginContributions.State.LOADED;
301
+ console.debug(`[${this.clientId}][${pluginId}]: Loaded contributions.`);
302
+ loaded++;
303
+ }
304
+
305
+ if (contributions.state === PluginContributions.State.LOADED) {
306
+ contributions.state = PluginContributions.State.STARTING;
307
+ const host = plugin.model.entryPoint.frontend ? 'frontend' : plugin.host;
308
+ const dynamicContributions = hostContributions.get(host) || [];
309
+ dynamicContributions.push(contributions);
310
+ hostContributions.set(host, dynamicContributions);
311
+ toDisconnect.push(Disposable.create(() => {
312
+ contributions!.state = PluginContributions.State.LOADED;
313
+ console.debug(`[${this.clientId}][${pluginId}]: Disconnected.`);
314
+ }));
315
+ }
316
+ }
317
+ if (loaded > 0) {
318
+ // Only log load measurement if there are were plugins to load.
319
+ loadPluginsMeasurement?.log(`Load contributions of ${this.getPluginCount(loaded)}`);
320
+ } else {
321
+ loadPluginsMeasurement.stop();
322
+ }
323
+
324
+ return hostContributions;
325
+ }
326
+
327
+ protected abstract handleContributions(plugin: DeployedPlugin): Disposable;
328
+
329
+ protected async startPlugins(contributionsByHost: Map<PluginHost, PluginContributions[]>, toDisconnect: DisposableCollection): Promise<void> {
330
+ let started = 0;
331
+ const startPluginsMeasurement = this.measure('startPlugins');
332
+
333
+ const [hostLogPath, hostStoragePath, hostGlobalStoragePath] = await Promise.all([
334
+ this.pluginPathsService.getHostLogPath(),
335
+ this.getStoragePath(),
336
+ this.getHostGlobalStoragePath()
337
+ ]);
338
+
339
+ if (toDisconnect.disposed) {
340
+ return;
341
+ }
342
+
343
+ const thenable: Promise<void>[] = [];
344
+ const configStorage: ConfigStorage = {
345
+ hostLogPath,
346
+ hostStoragePath,
347
+ hostGlobalStoragePath
348
+ };
349
+
350
+ for (const [host, hostContributions] of contributionsByHost) {
351
+ // do not start plugins for electron browser
352
+ if (host === 'frontend' && environment.electron.is()) {
353
+ continue;
354
+ }
355
+
356
+ const manager = await this.obtainManager(host, hostContributions, toDisconnect);
357
+ if (!manager) {
358
+ continue;
359
+ }
360
+
361
+ const plugins = hostContributions.map(contributions => contributions.plugin.metadata);
362
+ thenable.push((async () => {
363
+ try {
364
+ const activationEvents = [...this.activationEvents];
365
+ await manager.$start({ plugins, configStorage, activationEvents });
366
+ if (toDisconnect.disposed) {
367
+ return;
368
+ }
369
+ console.log(`[${this.clientId}] Starting plugins.`);
370
+ for (const contributions of hostContributions) {
371
+ started++;
372
+ const plugin = contributions.plugin;
373
+ const id = plugin.metadata.model.id;
374
+ contributions.state = PluginContributions.State.STARTED;
375
+ console.debug(`[${this.clientId}][${id}]: Started plugin.`);
376
+ toDisconnect.push(contributions.push(Disposable.create(() => {
377
+ console.debug(`[${this.clientId}][${id}]: Stopped plugin.`);
378
+ manager.$stop(id);
379
+ })));
380
+
381
+ this.handlePluginStarted(manager, plugin);
382
+ }
383
+ } catch (e) {
384
+ console.error(`Failed to start plugins for '${host}' host`, e);
385
+ }
386
+ })());
387
+ }
388
+
389
+ await Promise.all(thenable);
390
+ await this.activateByEvent('onStartupFinished');
391
+ if (toDisconnect.disposed) {
392
+ return;
393
+ }
394
+
395
+ if (started > 0) {
396
+ startPluginsMeasurement.log(`Start of ${this.getPluginCount(started)}`);
397
+ } else {
398
+ startPluginsMeasurement.stop();
399
+ }
400
+ }
401
+
402
+ protected abstract obtainManager(host: string, hostContributions: PluginContributions[],
403
+ toDisconnect: DisposableCollection): Promise<PM | undefined>;
404
+
405
+ protected abstract getStoragePath(): Promise<string | undefined>;
406
+
407
+ protected abstract getHostGlobalStoragePath(): Promise<string>;
408
+
409
+ async activateByEvent(activationEvent: string): Promise<void> {
410
+ if (this.activationEvents.has(activationEvent)) {
411
+ return;
412
+ }
413
+ this.activationEvents.add(activationEvent);
414
+ await Promise.all(Array.from(this.managers.values(), manager => manager.$activateByEvent(activationEvent)));
415
+ }
416
+
417
+ async activatePlugin(id: string): Promise<void> {
418
+ const activation = [];
419
+ for (const manager of this.managers.values()) {
420
+ activation.push(manager.$activatePlugin(id));
421
+ }
422
+ await Promise.all(activation);
423
+ }
424
+
425
+ protected handlePluginStarted(manager: PM, plugin: DeployedPlugin): void {
426
+ // Nothing to do in the abstract
427
+ }
428
+
429
+ protected measure(name: string): Measurement {
430
+ return this.stopwatch.start(name, { context: this.clientId });
431
+ }
432
+
433
+ protected getPluginCount(plugins: number): string {
434
+ return `${plugins} plugin${plugins === 1 ? '' : 's'}`;
435
+ }
436
+
437
+ }
438
+
439
+ export class PluginContributions extends DisposableCollection {
440
+ constructor(
441
+ readonly plugin: DeployedPlugin
442
+ ) {
443
+ super();
444
+ }
445
+ state: PluginContributions.State = PluginContributions.State.INITIALIZING;
446
+ }
447
+
448
+ export namespace PluginContributions {
449
+ export enum State {
450
+ INITIALIZING = 0,
451
+ LOADING = 1,
452
+ LOADED = 2,
453
+ STARTING = 3,
454
+ STARTED = 4
455
+ }
456
+ }
@@ -16,16 +16,16 @@
16
16
 
17
17
  import { ConnectionErrorHandler, ContributionProvider, ILogger, MessageService } from '@theia/core/lib/common';
18
18
  import { Deferred } from '@theia/core/lib/common/promise-util';
19
+ import { BinaryMessagePipe } from '@theia/core/lib/node/messaging/binary-message-pipe';
19
20
  import { createIpcEnv } from '@theia/core/lib/node/messaging/ipc-protocol';
20
21
  import { inject, injectable, named } from '@theia/core/shared/inversify';
21
22
  import * as cp from 'child_process';
23
+ import { Duplex } from 'stream';
24
+ import { DeployedPlugin, HostedPluginClient, PLUGIN_HOST_BACKEND, PluginHostEnvironmentVariable, PluginIdentifiers, ServerPluginRunner } from '../../common/plugin-protocol';
22
25
  import { HostedPluginCliContribution } from './hosted-plugin-cli-contribution';
23
26
  import { HostedPluginLocalizationService } from './hosted-plugin-localization-service';
24
- import { ProcessTerminatedMessage, ProcessTerminateMessage } from './hosted-plugin-protocol';
25
- import { BinaryMessagePipe } from '@theia/core/lib/node/messaging/binary-message-pipe';
26
- import { DeployedPlugin, HostedPluginClient, PluginHostEnvironmentVariable, PluginIdentifiers, PLUGIN_HOST_BACKEND, ServerPluginRunner } from '../../common/plugin-protocol';
27
+ import { ProcessTerminateMessage, ProcessTerminatedMessage } from './hosted-plugin-protocol';
27
28
  import psTree = require('ps-tree');
28
- import { Duplex } from 'stream';
29
29
 
30
30
  export interface IPCConnectionOptions {
31
31
  readonly serverName: string;
@@ -21,7 +21,7 @@ import { CliContribution } from '@theia/core/lib/node/cli';
21
21
  import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
22
22
  import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
23
23
  import { MetadataScanner } from './metadata-scanner';
24
- import { HostedPluginServerImpl } from './plugin-service';
24
+ import { BackendPluginHostableFilter, HostedPluginServerImpl } from './plugin-service';
25
25
  import { HostedPluginReader } from './plugin-reader';
26
26
  import { HostedPluginSupport } from './hosted-plugin';
27
27
  import { TheiaPluginScanner } from './scanners/scanner-theia';
@@ -38,6 +38,7 @@ import { LanguagePackService, languagePackServicePath } from '../../common/langu
38
38
  import { PluginLanguagePackService } from './plugin-language-pack-service';
39
39
  import { RpcConnectionHandler } from '@theia/core/lib/common/messaging/proxy-factory';
40
40
  import { ConnectionHandler } from '@theia/core/lib/common/messaging/handler';
41
+ import { isConnectionScopedBackendPlugin } from '../common/hosted-plugin';
41
42
 
42
43
  const commonHostedConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
43
44
  bind(HostedPluginProcess).toSelf().inSingletonScope();
@@ -48,6 +49,7 @@ const commonHostedConnectionModule = ConnectionContainerModule.create(({ bind, b
48
49
 
49
50
  bind(HostedPluginServerImpl).toSelf().inSingletonScope();
50
51
  bind(HostedPluginServer).toService(HostedPluginServerImpl);
52
+ bind(BackendPluginHostableFilter).toConstantValue(isConnectionScopedBackendPlugin);
51
53
  bindBackendService<HostedPluginServer, HostedPluginClient>(hostedServicePath, HostedPluginServer, (server, client) => {
52
54
  server.setClient(client);
53
55
  client.onDidCloseConnection(() => server.dispose());
@@ -0,0 +1,69 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ import '@theia/core/shared/reflect-metadata';
17
+ import { ContainerModule } from '@theia/core/shared/inversify';
18
+ import { RPCProtocol, RPCProtocolImpl } from '../../common/rpc-protocol';
19
+ import { AbstractPluginHostRPC, PluginHostRPC, PluginContainerModuleLoader } from './plugin-host-rpc';
20
+ import { AbstractPluginManagerExtImpl, MinimalTerminalServiceExt, PluginManagerExtImpl } from '../../plugin/plugin-manager';
21
+ import { IPCChannel } from '@theia/core/lib/node';
22
+ import { InternalPluginContainerModule } from '../../plugin/node/plugin-container-module';
23
+ import { LocalizationExt } from '../../common/plugin-api-rpc';
24
+ import { EnvExtImpl } from '../../plugin/env';
25
+ import { EnvNodeExtImpl } from '../../plugin/node/env-node-ext';
26
+ import { LocalizationExtImpl } from '../../plugin/localization-ext';
27
+ import { PreferenceRegistryExtImpl } from '../../plugin/preference-registry';
28
+ import { DebugExtImpl } from '../../plugin/debug/debug-ext';
29
+ import { EditorsAndDocumentsExtImpl } from '../../plugin/editors-and-documents';
30
+ import { WorkspaceExtImpl } from '../../plugin/workspace';
31
+ import { MessageRegistryExt } from '../../plugin/message-registry';
32
+ import { ClipboardExt } from '../../plugin/clipboard-ext';
33
+ import { KeyValueStorageProxy, InternalStorageExt } from '../../plugin/plugin-storage';
34
+ import { WebviewsExtImpl } from '../../plugin/webviews';
35
+ import { TerminalServiceExtImpl } from '../../plugin/terminal-ext';
36
+ import { InternalSecretsExt, SecretsExtImpl } from '../../plugin/secrets-ext';
37
+
38
+ export default new ContainerModule(bind => {
39
+ const channel = new IPCChannel();
40
+ bind(RPCProtocol).toConstantValue(new RPCProtocolImpl(channel));
41
+
42
+ bind(PluginContainerModuleLoader).toDynamicValue(({ container }) =>
43
+ (module: ContainerModule) => {
44
+ container.load(module);
45
+ const internalModule = module as InternalPluginContainerModule;
46
+ const pluginApiCache = internalModule.initializeApi?.(container);
47
+ return pluginApiCache;
48
+ }).inSingletonScope();
49
+
50
+ bind(AbstractPluginHostRPC).toService(PluginHostRPC);
51
+ bind(AbstractPluginManagerExtImpl).toService(PluginManagerExtImpl);
52
+ bind(PluginManagerExtImpl).toSelf().inSingletonScope();
53
+ bind(PluginHostRPC).toSelf().inSingletonScope();
54
+ bind(EnvExtImpl).to(EnvNodeExtImpl).inSingletonScope();
55
+ bind(LocalizationExt).to(LocalizationExtImpl).inSingletonScope();
56
+ bind(InternalStorageExt).toService(KeyValueStorageProxy);
57
+ bind(KeyValueStorageProxy).toSelf().inSingletonScope();
58
+ bind(InternalSecretsExt).toService(SecretsExtImpl);
59
+ bind(SecretsExtImpl).toSelf().inSingletonScope();
60
+ bind(PreferenceRegistryExtImpl).toSelf().inSingletonScope();
61
+ bind(DebugExtImpl).toSelf().inSingletonScope();
62
+ bind(EditorsAndDocumentsExtImpl).toSelf().inSingletonScope();
63
+ bind(WorkspaceExtImpl).toSelf().inSingletonScope();
64
+ bind(MessageRegistryExt).toSelf().inSingletonScope();
65
+ bind(ClipboardExt).toSelf().inSingletonScope();
66
+ bind(WebviewsExtImpl).toSelf().inSingletonScope();
67
+ bind(MinimalTerminalServiceExt).toService(TerminalServiceExtImpl);
68
+ bind(TerminalServiceExtImpl).toSelf().inSingletonScope();
69
+ });