iobroker.javascript 10.1.3 → 10.2.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 (131) hide show
  1. package/README.md +24 -47
  2. package/admin/assets/AiChatPanel-DzN_zJhJ.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-C4EMPnwD.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-1zrGeOYq.js +1 -0
  10. package/admin/assets/RulesEditor-CybrKL-9.css +1 -0
  11. package/admin/assets/ScriptEditor-DrKzMShn.js +2 -0
  12. package/admin/assets/ScriptEditorVanillaMonaco-uvElLaRp.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-LTtUGqJp.js +1 -0
  17. package/admin/assets/{blockly-DBw-ytY1.js → blockly-Fp-1_Ye3.js} +1 -1
  18. package/admin/assets/{blocks_action-CaHoI2vK.js → blocks_action-xqgGyzT2.js} +1 -1
  19. package/admin/assets/{blocks_convert-Dno4Uyat.js → blocks_convert-PyFGxenp.js} +1 -1
  20. package/admin/assets/{blocks_logic-C4MPyL6T.js → blocks_logic-BJxcqx2J.js} +1 -1
  21. package/admin/assets/{blocks_number-BMu9V-ca.js → blocks_number-xkiHAbop.js} +1 -1
  22. package/admin/assets/{blocks_object-vU59tx8A.js → blocks_object-D7_2tXgc.js} +1 -1
  23. package/admin/assets/{blocks_procedures-CfhGGNAK.js → blocks_procedures-BSaG5k0y.js} +1 -1
  24. package/admin/assets/{blocks_sendto-oZjHfEt6.js → blocks_sendto-CdFzuf2Q.js} +1 -1
  25. package/admin/assets/{blocks_switch-DtRe2uV0.js → blocks_switch-CRs6hqoN.js} +1 -1
  26. package/admin/assets/{blocks_system-CWkKMHLd.js → blocks_system-ImR4v_sW.js} +1 -1
  27. package/admin/assets/{blocks_text-CunCNUrR.js → blocks_text-BATVRS4q.js} +1 -1
  28. package/admin/assets/{blocks_time-B_Duc9-g.js → blocks_time-BhxMTQmg.js} +1 -1
  29. package/admin/assets/{blocks_timeout-B5PA_0Xv.js → blocks_timeout-BZ2hzRJk.js} +1 -1
  30. package/admin/assets/{blocks_trigger-BePNP-VV.js → blocks_trigger-bkOJ_uVI.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-Cbd0K4kn.js → helpers-DIT6UgRN.js} +1 -1
  37. package/admin/assets/{hostInit-PWanFl0v.js → hostInit-CzvCZFy5.js} +1 -1
  38. package/admin/assets/index-DwTLl2xB.js +871 -0
  39. package/admin/assets/inlineChatWidget-n7ufGLov.js +2 -0
  40. package/admin/assets/{inlineDiffController-CauFSimb.js → inlineDiffController-5u3tIcIH.js} +1 -1
  41. package/admin/assets/{mf-entry-bootstrap-0-66751765.js → mf-entry-bootstrap-0-bde4e47a.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-CxnK2NMF.js → hostInit-B0Qa8jfJ.js} +1 -1
  62. package/admin/custom/assets/index-DADYLUN0.js +1 -0
  63. package/admin/custom/assets/{lib-D4Fc4r7w.js → lib-BDVPOOMD.js} +2 -2
  64. package/admin/custom/assets/{mf-entry-bootstrap-0-16561517.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-PH1CCUgS.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 +54 -1
  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 +40 -7
  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 +202 -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-rQsCR89v.js +0 -242
  97. package/admin/assets/AiDiffView-BoglEOaq.js +0 -1
  98. package/admin/assets/AiInlineProvider-CaHd2G2Q.js +0 -5
  99. package/admin/assets/Debugger-Bj4PsKNm.js +0 -15
  100. package/admin/assets/Error-RANTMuGx.js +0 -1
  101. package/admin/assets/Import-CJgQwwNY.js +0 -1
  102. package/admin/assets/RulesEditor-BcGsf9n4.css +0 -1
  103. package/admin/assets/RulesEditor-PYpUIg7N.js +0 -1
  104. package/admin/assets/ScriptEditor-C6ekGK_v.js +0 -2
  105. package/admin/assets/ScriptEditorVanillaMonaco-BzazJaUa.js +0 -3
  106. package/admin/assets/_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CL_S1FIh.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-BAOcdAz5.js +0 -1243
  108. package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DdX5BXjB.js +0 -9
  109. package/admin/assets/aiPromptBuilder-a2bvj40X.js +0 -1
  110. package/admin/assets/cronHoverProvider-COaB74MF.js +0 -2
  111. package/admin/assets/field_cron-BkiRQvy7.js +0 -1
  112. package/admin/assets/field_oid-pEOMkwS7.js +0 -1
  113. package/admin/assets/field_script-D8TaeXTc.js +0 -1
  114. package/admin/assets/index-4M2aGX3M.js +0 -871
  115. package/admin/assets/inlineChatWidget-CmSJN0Rv.js +0 -2
  116. package/admin/assets/stateHoverProvider-g3dqXZ8K.js +0 -9
  117. package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-Dc9L2TVn.js +0 -1
  118. package/admin/custom/assets/Components-uxORfFYU.js +0 -1
  119. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-Bd9Y-jyc.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-BGJv4zZP.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-B4E6MFJ4.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-DMefPDeL.js +0 -1243
  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-D81YCXgE.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-CxkJmLDG.js +0 -9
  126. package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-BNLW3sTg.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-CHg-uG3r.js +0 -1
  129. package/admin/custom/assets/setYear-Dhce8K9j.js +0 -1
  130. package/admin/custom/assets/virtualExposes-DUFP2Erj.js +0 -1
  131. package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-jnBHXUID.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) {
@@ -891,6 +924,31 @@ class JavaScript extends adapter_core_1.Adapter {
891
924
  }
892
925
  return (0, aiProviderResolver_1.resolveProviderCredentials)(this.config, provider, opts.messageBaseUrl);
893
926
  }
927
+ /**
928
+ * Warns about the one setup that the fix for #2369 stops working.
929
+ *
930
+ * Until 10.1.3 a custom OpenAI-compatible endpoint was addressed as `provider: 'openai'`, so its
931
+ * requests were signed with the OpenAI key and routed to the custom URL. The documented
932
+ * workaround was therefore to put the *custom* endpoint's key into the OpenAI field. Both halves
933
+ * of that are gone now - the two providers no longer share a key or a URL - and such a setup
934
+ * would silently start answering 401. Deliberately no fallback to `gptKey`: that is what used to
935
+ * hand a real OpenAI key to a third-party host.
936
+ */
937
+ warnAboutMisplacedCustomAiKey() {
938
+ if (!(this.config.gptBaseUrl || '').trim()) {
939
+ return;
940
+ }
941
+ const manager = this.config.credentialType === 'manager';
942
+ const custom = manager
943
+ ? (0, aiProviderResolver_1.getProviderCredentialId)(this.config, 'custom')
944
+ : (this.config.gptBaseUrlKey || '').trim();
945
+ const openai = manager ? (0, aiProviderResolver_1.getProviderCredentialId)(this.config, 'openai') : (this.config.gptKey || '').trim();
946
+ if (!custom && openai) {
947
+ this.log.warn(`A custom AI endpoint ("${this.config.gptBaseUrl}") is configured, but its own API key is empty. ` +
948
+ `Requests to it are no longer signed with the OpenAI key - move the key of that endpoint into ` +
949
+ `the "Custom API key" field of the adapter settings.`);
950
+ }
951
+ }
894
952
  /**
895
953
  * In `manager` mode, subscribe to all configured AI credentials so that edits made in the
896
954
  * admin credential manager (Settings → Credentials) are picked up live, without restarting
@@ -999,7 +1057,19 @@ class JavaScript extends adapter_core_1.Adapter {
999
1057
  });
1000
1058
  }
1001
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
+ }
1002
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);
1003
1073
  // Load typings for the editor
1004
1074
  const typings = {};
1005
1075
  // try to load TypeScript lib files from disk
@@ -1156,6 +1226,8 @@ class JavaScript extends adapter_core_1.Adapter {
1156
1226
  const messages = obj.message?.messages;
1157
1227
  const tools = obj.message?.tools;
1158
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);
1159
1231
  const { apiKey, baseUrl } = await this.resolveAiCredentials(provider, {
1160
1232
  messageBaseUrl: obj.message?.baseUrl,
1161
1233
  });
@@ -1212,8 +1284,16 @@ class JavaScript extends adapter_core_1.Adapter {
1212
1284
  messages,
1213
1285
  stream: false,
1214
1286
  ...(tools?.length ? { tools } : {}),
1215
- // Disable thinking/reasoning for local models to save context and speed
1216
- ...(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
+ : {}),
1217
1297
  };
1218
1298
  }
1219
1299
  const body = JSON.stringify(bodyObj);
@@ -1229,7 +1309,7 @@ class JavaScript extends adapter_core_1.Adapter {
1229
1309
  const req = requestModule.request(url, {
1230
1310
  method: 'POST',
1231
1311
  headers: chatHeaders,
1232
- timeout: 600000,
1312
+ timeout: requestTimeout,
1233
1313
  ...(isHttps && this.config.allowSelfSignedCerts ? { rejectUnauthorized: false } : {}),
1234
1314
  }, res => {
1235
1315
  let data = '';
@@ -1287,7 +1367,7 @@ class JavaScript extends adapter_core_1.Adapter {
1287
1367
  });
1288
1368
  req.on('timeout', () => {
1289
1369
  req.destroy();
1290
- 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);
1291
1371
  });
1292
1372
  req.write(bodyBuffer);
1293
1373
  req.end();
@@ -1580,9 +1660,18 @@ class JavaScript extends adapter_core_1.Adapter {
1580
1660
  this.activeStr = `${this.namespace}.scriptEnabled.`;
1581
1661
  this.mods.fs = new protectFs_1.default(this.log, (0, adapter_core_1.getAbsoluteDefaultDataDir)());
1582
1662
  this.mods['fs/promises'] = this.mods.fs.promises; // to avoid require('fs/promises');
1583
- // The instance configuration is only available now, so the compiler has to be created again
1584
- // with the options the user has selected in the "TypeScript" tab
1585
- 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();
1586
1675
  // try to read TS declarations
1587
1676
  try {
1588
1677
  tsAmbient = {
@@ -1605,8 +1694,11 @@ class JavaScript extends adapter_core_1.Adapter {
1605
1694
  tsAmbient = {};
1606
1695
  }
1607
1696
  await this.installLibraries();
1608
- // Load the TS declarations for Node.js and all 3rd party modules
1609
- 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()`.
1610
1702
  await this.getData();
1611
1703
  this.context.scheduler = new scheduler_1.Scheduler(this.log, Date, this.mods.suncalc, this.config.latitude, this.config.longitude);
1612
1704
  await this.dayTimeSchedules();
@@ -1618,6 +1710,7 @@ class JavaScript extends adapter_core_1.Adapter {
1618
1710
  // In `manager` credential mode, subscribe to the configured AI credentials so changes in the
1619
1711
  // central credential store are picked up live (the keys are cached for the AI sendTo handlers).
1620
1712
  await this.subscribeAiCredentials();
1713
+ this.warnAboutMisplacedCustomAiKey();
1621
1714
  // Read the central credential store, so the scripts can use `SECRETS.<name>.<field>`.
1622
1715
  // Later changes are picked up in `onObjectChange`.
1623
1716
  await this.secretsManager.load(this.config.enableSecrets !== false);
@@ -1666,6 +1759,7 @@ class JavaScript extends adapter_core_1.Adapter {
1666
1759
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(obj._id);
1667
1760
  let tsCompiled;
1668
1761
  try {
1762
+ this.prepareTypings(true);
1669
1763
  tsCompiled = this.tsServer.compile(filename, transformedSource);
1670
1764
  }
1671
1765
  catch (err) {
@@ -1713,20 +1807,46 @@ class JavaScript extends adapter_core_1.Adapter {
1713
1807
  // javascript
1714
1808
  const sourceCode = obj.common.source;
1715
1809
  this.globalScript += `${sourceCode}\n`;
1716
- // try to compile the declarations so TypeScripts can use
1717
- // functions defined in global JavaScripts
1718
- const filename = (0, typescriptTools_1.scriptIdToTSFilename)(obj._id);
1719
- let tsCompiled;
1720
- try {
1721
- 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;
1722
1827
  }
1723
- catch (err) {
1724
- this.log.warn(`${obj._id}: Error while generating type declarations, skipping:\n${err}`);
1725
- 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
+ }
1726
1846
  }
1727
1847
  // if declarations were generated, remember them
1728
- if (tsCompiled.success && tsCompiled.declarations != null) {
1729
- this.provideDeclarationsForGlobalScript(obj._id, tsCompiled.declarations);
1848
+ if (declarations != null) {
1849
+ this.provideDeclarationsForGlobalScript(obj._id, declarations);
1730
1850
  }
1731
1851
  }
1732
1852
  }
@@ -1810,6 +1930,60 @@ class JavaScript extends adapter_core_1.Adapter {
1810
1930
  this.tsServer.provideAmbientDeclarations({ [declarationPath]: declarations });
1811
1931
  jsDeclarationServer.provideAmbientDeclarations({ [declarationPath]: declarations });
1812
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
+ }
1813
1987
  loadTypeScriptDeclarations() {
1814
1988
  // try to load the typings on disk for all 3rd party modules
1815
1989
  const packages = [
@@ -1868,6 +2042,8 @@ class JavaScript extends adapter_core_1.Adapter {
1868
2042
  }
1869
2043
  }
1870
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));
1871
2047
  // remember the declarations for the editor
1872
2048
  Object.assign(tsAmbient, pkgTypings);
1873
2049
  // and give the language servers access to them
@@ -2518,6 +2694,7 @@ class JavaScript extends adapter_core_1.Adapter {
2518
2694
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(name);
2519
2695
  let tsCompiled;
2520
2696
  try {
2697
+ this.prepareTypings(true);
2521
2698
  tsCompiled = this.tsServer.compile(filename, transformedSource);
2522
2699
  }
2523
2700
  catch (err) {
@@ -2918,6 +3095,7 @@ class JavaScript extends adapter_core_1.Adapter {
2918
3095
  const filename = (0, typescriptTools_1.scriptIdToTSFilename)(name);
2919
3096
  let tsCompiled;
2920
3097
  try {
3098
+ this.prepareTypings(true);
2921
3099
  tsCompiled = this.tsServer.compile(filename, transformedSource);
2922
3100
  }
2923
3101
  catch (err) {