iobroker.javascript 10.1.4 → 10.2.1

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 (131) hide show
  1. package/README.md +21 -48
  2. package/admin/assets/AiChatPanel-CsDFom-L.js +27 -0
  3. package/admin/assets/AiChatService-k72w0sOt.js +216 -0
  4. package/admin/assets/AiDiffView-DAleMXcP.js +1 -0
  5. package/admin/assets/AiInlineProvider-C5EJApDe.js +5 -0
  6. package/admin/assets/Debugger-B6_1wqlh.js +15 -0
  7. package/admin/assets/Error-DBiAAbCC.js +1 -0
  8. package/admin/assets/Import-Dm-2zYlI.js +1 -0
  9. package/admin/assets/RulesEditor-BML5AwgM.js +1 -0
  10. package/admin/assets/RulesEditor-CybrKL-9.css +1 -0
  11. package/admin/assets/ScriptEditor-BxwJbR3_.js +2 -0
  12. package/admin/assets/ScriptEditorVanillaMonaco-C3AgkXsv.js +3 -0
  13. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CQpJXcpz.js +1 -0
  14. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-Drq9CkPs.js +1217 -0
  15. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__113183188387379__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-B8K8J9cp.js +9 -0
  16. package/admin/assets/aiPromptBuilder-CuCGSQIi.js +1 -0
  17. package/admin/assets/{blockly-DBw-ytY1.js → blockly-Fp-1_Ye3.js} +1 -1
  18. package/admin/assets/{blocks_action-Dflw8PyN.js → blocks_action-CPgrbjAf.js} +1 -1
  19. package/admin/assets/{blocks_convert-XTqMxB04.js → blocks_convert-2eEzarQy.js} +1 -1
  20. package/admin/assets/{blocks_logic-JaZOQj6_.js → blocks_logic-DMEjFKWc.js} +1 -1
  21. package/admin/assets/{blocks_number-TU4dV-Ia.js → blocks_number-Bsx0zQT_.js} +1 -1
  22. package/admin/assets/{blocks_object-V6ojF22C.js → blocks_object-Q1nKLN6t.js} +1 -1
  23. package/admin/assets/{blocks_procedures-Cu8VeJhw.js → blocks_procedures-CHMjZQbf.js} +1 -1
  24. package/admin/assets/{blocks_sendto-BnDWzP0n.js → blocks_sendto-DsDq_Gu7.js} +1 -1
  25. package/admin/assets/{blocks_switch-DKUc060E.js → blocks_switch-Yog8S2MC.js} +1 -1
  26. package/admin/assets/{blocks_system-BW_UpMW-.js → blocks_system-2D8iX32Y.js} +1 -1
  27. package/admin/assets/{blocks_text-BIU2kf_V.js → blocks_text-C5-csrVL.js} +1 -1
  28. package/admin/assets/{blocks_time-2vgvS4_j.js → blocks_time-LB5i9yMW.js} +1 -1
  29. package/admin/assets/{blocks_timeout-BPzmWif8.js → blocks_timeout-CHGW670q.js} +1 -1
  30. package/admin/assets/{blocks_trigger-BSFZEWEO.js → blocks_trigger-D-2z_OfF.js} +1 -1
  31. package/admin/assets/cronHoverProvider-DYMf8M44.js +2 -0
  32. package/admin/assets/{dist-BF-PlO2i.js → dist-D4uJqRBO.js} +1 -1
  33. package/admin/assets/field_cron-B-SF-uZM.js +1 -0
  34. package/admin/assets/field_oid-fYE12Bhj.js +1 -0
  35. package/admin/assets/field_script-aZs3j-vG.js +1 -0
  36. package/admin/assets/{helpers-BFQD9R82.js → helpers-CalO_DDQ.js} +1 -1
  37. package/admin/assets/{hostInit-B_aW3Wuw.js → hostInit-CzvCZFy5.js} +1 -1
  38. package/admin/assets/index-CqFiN-25.js +871 -0
  39. package/admin/assets/inlineChatWidget-n7ufGLov.js +2 -0
  40. package/admin/assets/{inlineDiffController-DGl5rDYU.js → inlineDiffController-5u3tIcIH.js} +1 -1
  41. package/admin/assets/{mf-entry-bootstrap-0-ec2e487a.js → mf-entry-bootstrap-0-db6d825d.js} +14 -2
  42. package/admin/assets/pendingShares-C6DqQuMX.js +1 -0
  43. package/admin/assets/stateHoverProvider-C0OUV2Nh.js +9 -0
  44. package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-BvxK85AS.js +1 -0
  45. package/admin/assets/{vite-preload-helper-B7qeedMF.js → vite-preload-helper-CaC3yEL3.js} +1 -1
  46. package/admin/custom/assets/Components-qR8oYG5T.js +1 -0
  47. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-CB5V_0nT.js +1 -0
  48. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-Cc7MmJgr.js +1 -0
  49. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-CFSZkPFK.js +1 -0
  50. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-o8Mkax3s.js +1217 -0
  51. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-DLa2mE8b.js +1 -0
  52. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare___mf_0_mui_mf_1_x_mf_2_date_mf_2_pickers__loadShare__.js-CZc6K9E9.js +1 -0
  53. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare__date_mf_2_fns__loadShare__.js-Bx5h7ISf.js +1 -0
  54. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare__leaflet__loadShare__.js-im3edKNs.js +1 -0
  55. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-Ca3AhTHn.js +1 -0
  56. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-bDecxMAs.js +124 -0
  57. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__prebuild__leaflet__prebuild__-CAKlcuIS.js +1 -0
  58. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-Byvr2uOb.js +1 -0
  59. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__32150414352696__prebuild__react_mf_2_dom_mf_1_client__prebuild__-Thbi9Vo9.js +9 -0
  60. package/admin/custom/assets/dist-D4uJqRBO.js +4 -0
  61. package/admin/custom/assets/{hostInit-CkdLQZaZ.js → hostInit-B0Qa8jfJ.js} +1 -1
  62. package/admin/custom/assets/index-DADYLUN0.js +1 -0
  63. package/admin/custom/assets/{lib-D9tipKpE.js → lib-BDVPOOMD.js} +2 -2
  64. package/admin/custom/assets/{mf-entry-bootstrap-0-ff278fef.js → mf-entry-bootstrap-0-b41e47ad.js} +14 -2
  65. package/admin/custom/assets/pendingShares-Gn0OX49v.js +1 -0
  66. package/admin/custom/assets/virtualExposes-DjwWqUOb.js +1 -0
  67. package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-CHOLf9xJ.js +1 -0
  68. package/admin/custom/assets/{virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-C1DpedFv.js → virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-C0XlV8T_.js} +2 -2
  69. package/admin/custom/assets/{vite-preload-helper-B7qeedMF.js → vite-preload-helper-CaC3yEL3.js} +1 -1
  70. package/admin/custom/customComponents.js +2 -2
  71. package/admin/i18n/de.json +8 -2
  72. package/admin/i18n/en.json +8 -2
  73. package/admin/i18n/es.json +8 -2
  74. package/admin/i18n/fr.json +8 -2
  75. package/admin/i18n/it.json +8 -2
  76. package/admin/i18n/nl.json +8 -2
  77. package/admin/i18n/pl.json +8 -2
  78. package/admin/i18n/pt.json +8 -2
  79. package/admin/i18n/ru.json +8 -2
  80. package/admin/i18n/uk.json +8 -2
  81. package/admin/i18n/zh-cn.json +8 -2
  82. package/admin/jsonConfig.json +53 -0
  83. package/admin/mf-manifest.json +1 -1
  84. package/admin/mf-stats.json +1 -1
  85. package/admin/remoteEntry.js +2 -2
  86. package/admin/tab.html +5 -5
  87. package/build/lib/aiProviderResolver.js +22 -1
  88. package/build/lib/aiProviderResolver.js.map +1 -1
  89. package/build/lib/lazyTsServer.js +177 -0
  90. package/build/lib/lazyTsServer.js.map +1 -0
  91. package/build/main.js +176 -24
  92. package/build/main.js.map +1 -1
  93. package/build/types.d.ts +13 -0
  94. package/io-package.json +31 -28
  95. package/package.json +7 -8
  96. package/admin/assets/AiChatPanel-D93BBufl.js +0 -242
  97. package/admin/assets/AiDiffView-D5QZDwuC.js +0 -1
  98. package/admin/assets/AiInlineProvider-CRU2J938.js +0 -5
  99. package/admin/assets/Debugger-BLzsRkue.js +0 -15
  100. package/admin/assets/Error-BWXtkB6H.js +0 -1
  101. package/admin/assets/Import-D_RBSmNU.js +0 -1
  102. package/admin/assets/RulesEditor-DpKr8byp.js +0 -1
  103. package/admin/assets/RulesEditor-QNWIRnqB.css +0 -1
  104. package/admin/assets/ScriptEditor-DK6nNmcp.js +0 -2
  105. package/admin/assets/ScriptEditorVanillaMonaco-BVIwadsl.js +0 -3
  106. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-v3-PYsgp.js +0 -1
  107. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-GB0oxSwG.js +0 -1217
  108. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-SF46owzN.js +0 -9
  109. package/admin/assets/aiPromptBuilder-CtijdvYL.js +0 -1
  110. package/admin/assets/cronHoverProvider-BMVsvVuG.js +0 -2
  111. package/admin/assets/field_cron-Br4hxeLb.js +0 -1
  112. package/admin/assets/field_oid-ojNnLVGL.js +0 -1
  113. package/admin/assets/field_script-Bs925umq.js +0 -1
  114. package/admin/assets/index-BnLv569U.js +0 -871
  115. package/admin/assets/inlineChatWidget-BcLIwfEH.js +0 -2
  116. package/admin/assets/stateHoverProvider-XKm8a_93.js +0 -9
  117. package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-IRf47UYM.js +0 -1
  118. package/admin/custom/assets/Components-BpxzAzc7.js +0 -1
  119. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-wwYTJNxa.js +0 -1
  120. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-DzaRKfE_.js +0 -1
  121. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-B9fjpXOq.js +0 -1
  122. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-QxUxIFgP.js +0 -1217
  123. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-BUk3WHjQ.js +0 -1494
  124. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__leaflet__loadShare__.js-n2zIPi0L.js +0 -1
  125. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DqjU6PXX.js +0 -9
  126. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-CXAEcWml.js +0 -1
  127. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__leaflet__prebuild__-BeF0jEWM.js +0 -1
  128. package/admin/custom/assets/index-D2qJNee0.js +0 -1
  129. package/admin/custom/assets/setYear-DXk_Jooa.js +0 -1
  130. package/admin/custom/assets/virtualExposes-vH26J8jF.js +0 -1
  131. package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-qdaLIbFV.js +0 -1
package/build/main.js CHANGED
@@ -73,6 +73,7 @@ const axios = __importStar(require("axios"));
73
73
  const wake_on_lan = __importStar(require("wake_on_lan"));
74
74
  const nodeSchedule = __importStar(require("node-schedule"));
75
75
  const adapter_core_1 = require("@iobroker/adapter-core");
76
+ const lazyTsServer_1 = require("./lib/lazyTsServer");
76
77
  const mirror_1 = require("./lib/mirror");
77
78
  const protectFs_1 = __importDefault(require("./lib/protectFs"));
78
79
  const words_1 = require("./lib/words");
@@ -226,8 +227,24 @@ function formatHoursMinutesSeconds(date) {
226
227
  (0, virtual_tsc_1.setTypeScriptResolveOptions)({
227
228
  paths: [require.resolve('typescript')],
228
229
  });
229
- // compiler instance for global JS declarations
230
- const jsDeclarationServer = new virtual_tsc_1.Server(typescriptSettings_1.jsDeclarationCompilerOptions, isCI ? false : undefined);
230
+ /**
231
+ * How long a TypeScript language service may keep its program and type checker after the last
232
+ * compilation. They are what makes the compiler expensive (~95 MB heap each), and scripts are
233
+ * compiled in bursts - at startup and when the user saves one - so after a minute of quiet the
234
+ * memory is better given back. The next compilation rebuilds it in about a second.
235
+ * See https://github.com/ioBroker/ioBroker.javascript/issues/2373
236
+ */
237
+ const TS_MEMORY_RELEASE_DELAY_MS = 60_000;
238
+ /**
239
+ * How long a script editor counts as open after its last sign of life. The editor pings the adapter
240
+ * every 10 seconds while its tab is visible; after this long without a ping the GUI is considered
241
+ * gone and the type definitions and compilers are given back.
242
+ */
243
+ const EDITOR_ONLINE_TIMEOUT_MS = 30_000;
244
+ /** How often it is checked whether the editor has gone away */
245
+ const EDITOR_CHECK_INTERVAL_MS = 10_000;
246
+ // compiler instance for global JS declarations. Built on the first compilation only - see LazyTsServer
247
+ const jsDeclarationServer = new lazyTsServer_1.LazyTsServer(typescriptSettings_1.jsDeclarationCompilerOptions, isCI ? false : undefined, TS_MEMORY_RELEASE_DELAY_MS);
231
248
  /**
232
249
  * Stores the IDs of script objects whose change should be ignored because
233
250
  * the compiled source was just updated
@@ -343,8 +360,18 @@ class JavaScript extends adapter_core_1.Adapter {
343
360
  globalScriptLines = 0;
344
361
  /** Running counter to build unique names for ad-hoc scripts started via the "execute" message */
345
362
  executeCounter = 0;
346
- // compiler instance for typescript
363
+ // compiler instance for typescript. Built on the first compilation only - see LazyTsServer
347
364
  tsServer;
365
+ /** Set once the type definitions have been read from disk - see `prepareTypings()` */
366
+ typingsLoaded = false;
367
+ /** The declaration files that came from the packages, so they can be given back again */
368
+ typingPackageFiles = [];
369
+ /** Until when a script editor counts as open. Refreshed by every `editorPing` */
370
+ editorOnlineUntil = 0;
371
+ /** Checks regularly whether the editor is gone and the type definitions can be unloaded */
372
+ editorCheckInterval = null;
373
+ /** Set once the user has been told that TypeScript is compiled without type definitions */
374
+ typingsWarningShown = false;
348
375
  logCollectors = [];
349
376
  ignoreObjectChange = new Set();
350
377
  debugState = {
@@ -487,7 +514,7 @@ class JavaScript extends adapter_core_1.Adapter {
487
514
  allowSelfSignedCerts: false,
488
515
  secrets: this.secretsManager.secrets,
489
516
  };
490
- this.tsServer = new virtual_tsc_1.Server(typescriptSettings_1.tsCompilerOptions, this.tsLog);
517
+ this.tsServer = new lazyTsServer_1.LazyTsServer(typescriptSettings_1.tsCompilerOptions, this.tsLog, TS_MEMORY_RELEASE_DELAY_MS);
491
518
  }
492
519
  async onObjectChange(id, obj) {
493
520
  // Check if we should ignore this change (once!) because we just updated the compiled sources
@@ -795,6 +822,12 @@ class JavaScript extends adapter_core_1.Adapter {
795
822
  }
796
823
  await this.unsubscribeAiCredentials();
797
824
  this.secretsManager.destroy();
825
+ if (this.editorCheckInterval) {
826
+ clearInterval(this.editorCheckInterval);
827
+ this.editorCheckInterval = null;
828
+ }
829
+ this.tsServer.destroy();
830
+ jsDeclarationServer.destroy();
798
831
  await this.stopAllScripts();
799
832
  }
800
833
  catch (err) {
@@ -1024,7 +1057,19 @@ class JavaScript extends adapter_core_1.Adapter {
1024
1057
  });
1025
1058
  }
1026
1059
  break;
1060
+ case 'editorPing': {
1061
+ // A script editor says it is still open. As long as that is the case, the type
1062
+ // definitions and the compilers stay in memory, so saving a script stays fast.
1063
+ this.editorOnlineUntil = Date.now() + EDITOR_ONLINE_TIMEOUT_MS;
1064
+ if (obj.callback) {
1065
+ this.sendTo(obj.from, obj.command, { ok: true }, obj.callback);
1066
+ }
1067
+ break;
1068
+ }
1027
1069
  case 'loadTypings': {
1070
+ // The editor is asking - now the type definitions are worth their memory
1071
+ this.editorOnlineUntil = Date.now() + EDITOR_ONLINE_TIMEOUT_MS;
1072
+ this.prepareTypings(false);
1028
1073
  // Load typings for the editor
1029
1074
  const typings = {};
1030
1075
  // try to load TypeScript lib files from disk
@@ -1181,6 +1226,8 @@ class JavaScript extends adapter_core_1.Adapter {
1181
1226
  const messages = obj.message?.messages;
1182
1227
  const tools = obj.message?.tools;
1183
1228
  const provider = (obj.message?.provider || 'openai').trim();
1229
+ // How long the caller is willing to wait - see `resolveRequestTimeout`
1230
+ const requestTimeout = (0, aiProviderResolver_1.resolveRequestTimeout)(obj.message?.timeout);
1184
1231
  const { apiKey, baseUrl } = await this.resolveAiCredentials(provider, {
1185
1232
  messageBaseUrl: obj.message?.baseUrl,
1186
1233
  });
@@ -1237,8 +1284,16 @@ class JavaScript extends adapter_core_1.Adapter {
1237
1284
  messages,
1238
1285
  stream: false,
1239
1286
  ...(tools?.length ? { tools } : {}),
1240
- // Disable thinking/reasoning for local models to save context and speed
1241
- ...(baseUrl ? { reasoning_effort: 'none' } : {}),
1287
+ /*
1288
+ * `reasoning_effort` used to be pinned to `none` for every custom base URL,
1289
+ * to save context and time on a local model. Behind a proxy that fronts a
1290
+ * subscription, the same setting turns off the reasoning the model is being
1291
+ * used for, or is rejected outright. It is a setting now, and the default is
1292
+ * to leave the parameter out and let the endpoint decide.
1293
+ */
1294
+ ...(this.config.aiReasoningEffort
1295
+ ? { reasoning_effort: this.config.aiReasoningEffort }
1296
+ : {}),
1242
1297
  };
1243
1298
  }
1244
1299
  const body = JSON.stringify(bodyObj);
@@ -1254,7 +1309,7 @@ class JavaScript extends adapter_core_1.Adapter {
1254
1309
  const req = requestModule.request(url, {
1255
1310
  method: 'POST',
1256
1311
  headers: chatHeaders,
1257
- timeout: 600000,
1312
+ timeout: requestTimeout,
1258
1313
  ...(isHttps && this.config.allowSelfSignedCerts ? { rejectUnauthorized: false } : {}),
1259
1314
  }, res => {
1260
1315
  let data = '';
@@ -1312,7 +1367,7 @@ class JavaScript extends adapter_core_1.Adapter {
1312
1367
  });
1313
1368
  req.on('timeout', () => {
1314
1369
  req.destroy();
1315
- this.sendTo(obj.from, obj.command, { error: 'Connection timeout (600s)' }, obj.callback);
1370
+ this.sendTo(obj.from, obj.command, { error: `Connection timeout (${Math.round(requestTimeout / 1000)}s)` }, obj.callback);
1316
1371
  });
1317
1372
  req.write(bodyBuffer);
1318
1373
  req.end();
@@ -1605,9 +1660,18 @@ class JavaScript extends adapter_core_1.Adapter {
1605
1660
  this.activeStr = `${this.namespace}.scriptEnabled.`;
1606
1661
  this.mods.fs = new protectFs_1.default(this.log, (0, adapter_core_1.getAbsoluteDefaultDataDir)());
1607
1662
  this.mods['fs/promises'] = this.mods.fs.promises; // to avoid require('fs/promises');
1608
- // The instance configuration is only available now, so the compiler has to be created again
1609
- // with the options the user has selected in the "TypeScript" tab
1610
- this.tsServer = new virtual_tsc_1.Server((0, typescriptSettings_1.getTsCompilerOptions)(this.config), this.tsLog);
1663
+ // The instance configuration is only available now, so the compiler gets the options
1664
+ // the user has selected in the "TypeScript" tab. Nothing was compiled yet, so this
1665
+ // does not throw any work away.
1666
+ this.tsServer.setOptions((0, typescriptSettings_1.getTsCompilerOptions)(this.config));
1667
+ // As long as a script editor is open, the compilers keep their program, so saving a script
1668
+ // does not have to wait for it to be built again
1669
+ const editorIsOpen = () => this.isEditorOnline();
1670
+ this.tsServer.setKeepAlive(editorIsOpen);
1671
+ jsDeclarationServer.setKeepAlive(editorIsOpen);
1672
+ // ... and once it has been closed for a while, everything is given back
1673
+ this.editorCheckInterval = setInterval(() => this.unloadTypings(), EDITOR_CHECK_INTERVAL_MS);
1674
+ this.editorCheckInterval.unref();
1611
1675
  // try to read TS declarations
1612
1676
  try {
1613
1677
  tsAmbient = {
@@ -1630,8 +1694,11 @@ class JavaScript extends adapter_core_1.Adapter {
1630
1694
  tsAmbient = {};
1631
1695
  }
1632
1696
  await this.installLibraries();
1633
- // Load the TS declarations for Node.js and all 3rd party modules
1634
- this.loadTypeScriptDeclarations();
1697
+ // The TS declarations for Node.js and the 3rd party modules are NOT read here. Only two things
1698
+ // need them - compiling a TypeScript script and the autocompletion of the built-in editor - and
1699
+ // they are not free: 2.5 MB of declaration files that add about 90 MB to the compiler's program.
1700
+ // An instance that runs plain JavaScript and is edited elsewhere never asks for them, and then
1701
+ // they are never read. See `prepareTypings()`.
1635
1702
  await this.getData();
1636
1703
  this.context.scheduler = new scheduler_1.Scheduler(this.log, Date, this.mods.suncalc, this.config.latitude, this.config.longitude);
1637
1704
  await this.dayTimeSchedules();
@@ -1692,6 +1759,7 @@ class JavaScript extends adapter_core_1.Adapter {
1692
1759
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(obj._id);
1693
1760
  let tsCompiled;
1694
1761
  try {
1762
+ this.prepareTypings(true);
1695
1763
  tsCompiled = this.tsServer.compile(filename, transformedSource);
1696
1764
  }
1697
1765
  catch (err) {
@@ -1739,20 +1807,46 @@ class JavaScript extends adapter_core_1.Adapter {
1739
1807
  // javascript
1740
1808
  const sourceCode = obj.common.source;
1741
1809
  this.globalScript += `${sourceCode}\n`;
1742
- // try to compile the declarations so TypeScripts can use
1743
- // functions defined in global JavaScripts
1744
- const filename = (0, typescriptTools_1.scriptIdToTSFilename)(obj._id);
1745
- let tsCompiled;
1746
- try {
1747
- tsCompiled = jsDeclarationServer.compile(filename, sourceCode);
1810
+ // The declarations let TypeScripts use the functions defined in global
1811
+ // JavaScripts. Generating them means building the whole TypeScript program,
1812
+ // which costs a second or two and around 95 MB of heap - and it has to happen
1813
+ // in every instance, because global scripts do not belong to one. So the
1814
+ // result is stored on the object, the same way the compiled TypeScript
1815
+ // sources are, and only generated again when the source or the declarations
1816
+ // of the global scripts before this one have changed.
1817
+ // The prefix keeps this hash apart from the one the TypeScript branch
1818
+ // writes: a script that is switched between JavaScript and TypeScript
1819
+ // must never accept the stored result of the other engine.
1820
+ const sourceHash = (0, tools_1.hashSource)(`${tsSourceHashBase},jsDeclarations${this.globalDeclarations}${sourceCode}`);
1821
+ let declarations;
1822
+ if (typeof obj.common.declarations === 'string' &&
1823
+ typeof obj.common.sourceHash === 'string' &&
1824
+ sourceHash === obj.common.sourceHash) {
1825
+ // We can reuse the stored declarations
1826
+ declarations = obj.common.declarations;
1748
1827
  }
1749
- catch (err) {
1750
- this.log.warn(`${obj._id}: Error while generating type declarations, skipping:\n${err}`);
1751
- continue;
1828
+ else {
1829
+ const filename = (0, typescriptTools_1.scriptIdToTSFilename)(obj._id);
1830
+ let tsCompiled;
1831
+ try {
1832
+ tsCompiled = jsDeclarationServer.compile(filename, sourceCode);
1833
+ }
1834
+ catch (err) {
1835
+ this.log.warn(`${obj._id}: Error while generating type declarations, skipping:\n${err}`);
1836
+ continue;
1837
+ }
1838
+ if (tsCompiled.success && tsCompiled.declarations != null) {
1839
+ declarations = tsCompiled.declarations;
1840
+ // Store them, so the next start does not have to build the program again
1841
+ this.ignoreObjectChange.add(obj._id); // ignore the next change and don't restart scripts
1842
+ void this.extendForeignObject(obj._id, {
1843
+ common: { sourceHash, declarations },
1844
+ });
1845
+ }
1752
1846
  }
1753
1847
  // if declarations were generated, remember them
1754
- if (tsCompiled.success && tsCompiled.declarations != null) {
1755
- this.provideDeclarationsForGlobalScript(obj._id, tsCompiled.declarations);
1848
+ if (declarations != null) {
1849
+ this.provideDeclarationsForGlobalScript(obj._id, declarations);
1756
1850
  }
1757
1851
  }
1758
1852
  }
@@ -1836,6 +1930,60 @@ class JavaScript extends adapter_core_1.Adapter {
1836
1930
  this.tsServer.provideAmbientDeclarations({ [declarationPath]: declarations });
1837
1931
  jsDeclarationServer.provideAmbientDeclarations({ [declarationPath]: declarations });
1838
1932
  }
1933
+ /**
1934
+ * Makes sure the type definitions of Node.js, ioBroker and the configured libraries are available.
1935
+ * Called right before the two things that need them: compiling a TypeScript script and answering
1936
+ * the editor's request for the typings. Everything else - running JavaScript, generating the
1937
+ * declarations of a global JavaScript - works without them, and an instance that only does that
1938
+ * never reads them at all.
1939
+ *
1940
+ * When the user switched them off, a TypeScript compilation is warned about once: without them the
1941
+ * compiler does not know `require`, `process` or `Buffer`, so the script very likely fails to
1942
+ * compile - and the reason would otherwise not be obvious.
1943
+ *
1944
+ * @param forTypeScript Whether a TypeScript compilation is about to happen (only then it is worth warning)
1945
+ */
1946
+ prepareTypings(forTypeScript) {
1947
+ if (this.config.loadTypings === false) {
1948
+ if (forTypeScript && !this.typingsWarningShown) {
1949
+ this.typingsWarningShown = true;
1950
+ this.log.warn('A TypeScript script is compiled, but "Load type definitions" is switched off in the instance settings. ' +
1951
+ 'Node.js and ioBroker types are unknown to the compiler, which will most likely fail the compilation.');
1952
+ }
1953
+ return;
1954
+ }
1955
+ if (this.typingsLoaded || !tsAmbient) {
1956
+ return;
1957
+ }
1958
+ this.typingsLoaded = true;
1959
+ this.loadTypeScriptDeclarations();
1960
+ }
1961
+ /** Whether a script editor has recently said that it is open */
1962
+ isEditorOnline() {
1963
+ return Date.now() < this.editorOnlineUntil;
1964
+ }
1965
+ /**
1966
+ * Gives the type definitions back once no editor is open any more. Only the files that were read
1967
+ * from the packages are dropped - the declarations of the global scripts are generated and cannot
1968
+ * be read again, so they stay. The compilers are thrown away with them, which also frees the
1969
+ * `lib*.d.ts` in their virtual file systems. The next TypeScript compilation or editor request
1970
+ * reads everything again.
1971
+ */
1972
+ unloadTypings() {
1973
+ if (!this.typingsLoaded || this.isEditorOnline()) {
1974
+ return;
1975
+ }
1976
+ this.log.debug(`No script editor open - releasing the type definitions (${this.typingPackageFiles.length} files)`);
1977
+ for (const fileName of this.typingPackageFiles) {
1978
+ delete tsAmbient[fileName];
1979
+ }
1980
+ this.tsServer.forgetDeclarations(this.typingPackageFiles);
1981
+ jsDeclarationServer.forgetDeclarations(this.typingPackageFiles);
1982
+ this.tsServer.unload();
1983
+ jsDeclarationServer.unload();
1984
+ this.typingPackageFiles = [];
1985
+ this.typingsLoaded = false;
1986
+ }
1839
1987
  loadTypeScriptDeclarations() {
1840
1988
  // try to load the typings on disk for all 3rd party modules
1841
1989
  const packages = [
@@ -1894,6 +2042,8 @@ class JavaScript extends adapter_core_1.Adapter {
1894
2042
  }
1895
2043
  }
1896
2044
  this.log.debug(`Loaded TypeScript definitions for "${pkg}": ${JSON.stringify(Object.keys(pkgTypings))}`);
2045
+ // remember which files these were, so they can be given back when nobody needs them
2046
+ this.typingPackageFiles.push(...Object.keys(pkgTypings));
1897
2047
  // remember the declarations for the editor
1898
2048
  Object.assign(tsAmbient, pkgTypings);
1899
2049
  // and give the language servers access to them
@@ -2544,6 +2694,7 @@ class JavaScript extends adapter_core_1.Adapter {
2544
2694
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(name);
2545
2695
  let tsCompiled;
2546
2696
  try {
2697
+ this.prepareTypings(true);
2547
2698
  tsCompiled = this.tsServer.compile(filename, transformedSource);
2548
2699
  }
2549
2700
  catch (err) {
@@ -2944,6 +3095,7 @@ class JavaScript extends adapter_core_1.Adapter {
2944
3095
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(name);
2945
3096
  let tsCompiled;
2946
3097
  try {
3098
+ this.prepareTypings(true);
2947
3099
  tsCompiled = this.tsServer.compile(filename, transformedSource);
2948
3100
  }
2949
3101
  catch (err) {