@mudlet/mudlet-web 0.5.0 → 1.0.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 (301) hide show
  1. package/README.md +1 -1
  2. package/dist-lib/analytics.d.ts +27 -0
  3. package/dist-lib/assets/fonts/Vera.woff2 +0 -0
  4. package/dist-lib/assets/fonts/VeraBI.woff2 +0 -0
  5. package/dist-lib/assets/fonts/VeraBd.woff2 +0 -0
  6. package/dist-lib/assets/fonts/VeraIt.woff2 +0 -0
  7. package/dist-lib/assets/mapParser.worker-DrVZ3wg_.js +9 -0
  8. package/dist-lib/backupImport-wt8r7JXI.js +233 -0
  9. package/dist-lib/branding.d.ts +111 -13
  10. package/dist-lib/db/sqliteClient.d.ts +195 -7
  11. package/dist-lib/hooks/useAutoReconnect.d.ts +61 -0
  12. package/dist-lib/hooks/useDocumentFullscreen.d.ts +23 -0
  13. package/dist-lib/hooks/useKeyboardShortcuts.d.ts +37 -0
  14. package/dist-lib/hooks/useRecordLastPlayed.d.ts +10 -0
  15. package/dist-lib/import/applyMudletProfile.d.ts +35 -9
  16. package/dist-lib/import/backupImport.d.ts +118 -0
  17. package/dist-lib/import/collectProfileExport.d.ts +33 -2
  18. package/dist-lib/import/defaultPackages.d.ts +57 -14
  19. package/dist-lib/import/defaults/CF-loader/CF-loader.mpackage +0 -0
  20. package/dist-lib/import/defaults/MedBootstrap/MedBootstrap.mpackage +0 -0
  21. package/dist-lib/import/defaults/deleteOldProfiles/deleteOldProfiles.mpackage +0 -0
  22. package/dist-lib/import/defaults/echo/echo.mpackage +0 -0
  23. package/dist-lib/import/defaults/enable-accessibility/enable-accessibility.mpackage +0 -0
  24. package/dist-lib/import/defaults/generic_mapper/generic_mapper.mpackage +0 -0
  25. package/dist-lib/import/defaults/gui-drop/gui-drop.mpackage +0 -0
  26. package/dist-lib/import/defaults/icesus-loader/icesus-loader.mpackage +0 -0
  27. package/dist-lib/import/defaults/mg-loader/mg-loader.mpackage +0 -0
  28. package/dist-lib/import/defaults/mudlet-base-ui/mudlet-base-ui.mpackage +0 -0
  29. package/dist-lib/import/defaults/mudlet-mapper.xml +1215 -389
  30. package/dist-lib/import/mudletControlChars.d.ts +14 -0
  31. package/dist-lib/import/mudletHost.d.ts +73 -10
  32. package/dist-lib/import/mudletLink.d.ts +53 -2
  33. package/dist-lib/import/mudletProfileExport.d.ts +38 -5
  34. package/dist-lib/import/mudletProfileImport.d.ts +110 -12
  35. package/dist-lib/import/mudletVariables.d.ts +4 -3
  36. package/dist-lib/import/mudletWriteback.d.ts +15 -1
  37. package/dist-lib/import/mudletXmlImport.d.ts +46 -0
  38. package/dist-lib/import/packageFonts.d.ts +33 -0
  39. package/dist-lib/import/packageInstaller.d.ts +111 -7
  40. package/dist-lib/import/qtProfileData.d.ts +10 -0
  41. package/dist-lib/import/remotePackageInstall.d.ts +23 -7
  42. package/dist-lib/import/zipEntries.d.ts +45 -0
  43. package/dist-lib/index.d.ts +7 -3
  44. package/dist-lib/index.js +50508 -29836
  45. package/dist-lib/logging/SessionLogger.d.ts +75 -15
  46. package/dist-lib/map/MapSelectionOverlay.d.ts +2 -2
  47. package/dist-lib/map/MapStore.d.ts +387 -60
  48. package/dist-lib/map/MudletHighlightOverlay.d.ts +2 -2
  49. package/dist-lib/map/{MudixMapReader.d.ts → MudletMapReader.d.ts} +2 -2
  50. package/dist-lib/map/areaGraph.d.ts +120 -0
  51. package/dist-lib/map/environmentKit.d.ts +36 -0
  52. package/dist-lib/map/labelPixmap.d.ts +90 -0
  53. package/dist-lib/map/mapImageExport.d.ts +36 -2
  54. package/dist-lib/map/mapStyle.d.ts +11 -0
  55. package/dist-lib/map/mapVersion.d.ts +66 -0
  56. package/dist-lib/map/pathfinding.d.ts +2 -2
  57. package/dist-lib/mud/CharLoginController.d.ts +230 -0
  58. package/dist-lib/mud/ItemIdSequence.d.ts +1 -1
  59. package/dist-lib/mud/MudSession.d.ts +279 -22
  60. package/dist-lib/mud/PatternEngine.d.ts +153 -14
  61. package/dist-lib/mud/aliases/AliasEngine.d.ts +55 -9
  62. package/dist-lib/mud/autoLogin.d.ts +59 -0
  63. package/dist-lib/mud/commandSplit.d.ts +9 -0
  64. package/dist-lib/mud/connection/LineAssembler.d.ts +38 -11
  65. package/dist-lib/mud/connection/MudClient.d.ts +291 -53
  66. package/dist-lib/mud/connection/SubnegotiationRepair.d.ts +24 -0
  67. package/dist-lib/mud/connection/TelnetNegotiator.d.ts +208 -68
  68. package/dist-lib/mud/connection/telnetDebug.d.ts +8 -8
  69. package/dist-lib/mud/events.d.ts +102 -23
  70. package/dist-lib/mud/games/bundledGames.d.ts +12 -7
  71. package/dist-lib/mud/games/gameLinks.d.ts +40 -0
  72. package/dist-lib/mud/games/icons/3Kingdoms.png +0 -0
  73. package/dist-lib/mud/games/icons/3Scapes.png +0 -0
  74. package/dist-lib/mud/games/icons/achaea.png +0 -0
  75. package/dist-lib/mud/games/icons/aetolia.png +0 -0
  76. package/dist-lib/mud/games/icons/banner_astaria.png +0 -0
  77. package/dist-lib/mud/games/icons/banner_darkmists.png +0 -0
  78. package/dist-lib/mud/games/icons/banner_dreamland.png +0 -0
  79. package/dist-lib/mud/games/icons/banner_petria.jpg +0 -0
  80. package/dist-lib/mud/games/icons/banner_ropmud.png +0 -0
  81. package/dist-lib/mud/games/icons/blackmud.png +0 -0
  82. package/dist-lib/mud/games/icons/carrionfields.png +0 -0
  83. package/dist-lib/mud/games/icons/dragonfire_icon.png +0 -0
  84. package/dist-lib/mud/games/icons/fed2-logo.png +0 -0
  85. package/dist-lib/mud/games/icons/icesus_480x120.png +0 -0
  86. package/dist-lib/mud/games/icons/imperian.png +0 -0
  87. package/dist-lib/mud/games/icons/infinity_480x120.png +0 -0
  88. package/dist-lib/mud/games/icons/lusternia.png +0 -0
  89. package/dist-lib/mud/games/icons/morgengrauen_480x120.png +0 -0
  90. package/dist-lib/mud/games/icons/mudlet-tutorial.png +0 -0
  91. package/dist-lib/mud/games/icons/phoenixmud_480x120.png +0 -0
  92. package/dist-lib/mud/games/icons/starmourn.png +0 -0
  93. package/dist-lib/mud/games/icons/voidmud_icon.png +0 -0
  94. package/dist-lib/mud/games/icons/wotmudicon.png +0 -0
  95. package/dist-lib/mud/games/websiteLinks.d.ts +21 -0
  96. package/dist-lib/mud/keybindings/KeyEngine.d.ts +110 -4
  97. package/dist-lib/mud/keybindings/browserReservedKeys.d.ts +2 -2
  98. package/dist-lib/mud/keybindings/keyEventTarget.d.ts +61 -0
  99. package/dist-lib/mud/keybindings/qtKeys.d.ts +91 -12
  100. package/dist-lib/mud/protocol/atcp.d.ts +19 -0
  101. package/dist-lib/mud/protocol/byteString.d.ts +24 -0
  102. package/dist-lib/mud/protocol/charLoginFlow.d.ts +243 -16
  103. package/dist-lib/mud/protocol/charset.d.ts +111 -46
  104. package/dist-lib/mud/protocol/codePages.d.ts +10 -0
  105. package/dist-lib/mud/protocol/constants.d.ts +17 -10
  106. package/dist-lib/mud/protocol/echo.d.ts +23 -27
  107. package/dist-lib/mud/protocol/gmcp.d.ts +36 -6
  108. package/dist-lib/mud/protocol/index.d.ts +3 -2
  109. package/dist-lib/mud/protocol/luaLiteral.d.ts +12 -0
  110. package/dist-lib/mud/protocol/mccp.d.ts +83 -1
  111. package/dist-lib/mud/protocol/mnes.d.ts +41 -58
  112. package/dist-lib/mud/protocol/msdp.d.ts +11 -4
  113. package/dist-lib/mud/protocol/msp.d.ts +3 -2
  114. package/dist-lib/mud/protocol/mssp.d.ts +9 -4
  115. package/dist-lib/mud/protocol/multiByte.d.ts +51 -0
  116. package/dist-lib/mud/protocol/multiByteEncode.d.ts +42 -0
  117. package/dist-lib/mud/protocol/mxp.d.ts +193 -14
  118. package/dist-lib/mud/protocol/oauthClientFlow.d.ts +128 -0
  119. package/dist-lib/mud/protocol/qtCodePages.generated.d.ts +1 -0
  120. package/dist-lib/mud/protocol/tlsCodes.d.ts +40 -3
  121. package/dist-lib/mud/replay/ReplayPlayer.d.ts +16 -1
  122. package/dist-lib/mud/replay/replayFormat.d.ts +29 -2
  123. package/dist-lib/mud/text/Console.d.ts +255 -49
  124. package/dist-lib/mud/text/FormatState.d.ts +137 -14
  125. package/dist-lib/mud/text/ansiEscapes.d.ts +32 -16
  126. package/dist-lib/mud/text/colorParsers.d.ts +14 -2
  127. package/dist-lib/mud/text/colorSpaceId.d.ts +2 -0
  128. package/dist-lib/mud/text/colors.d.ts +17 -10
  129. package/dist-lib/mud/text/controlCharacterMode.d.ts +1 -1
  130. package/dist-lib/mud/text/hyperlinkVisibility.d.ts +1 -1
  131. package/dist-lib/mud/text/lineBreak.d.ts +5 -0
  132. package/dist-lib/mud/text/serverWrap.d.ts +2 -2
  133. package/dist-lib/mud/text/textAnalyzer.d.ts +79 -0
  134. package/dist-lib/mud/text/unicodeRuns.d.ts +11 -0
  135. package/dist-lib/mud/text/unicodeTables.generated.d.ts +3 -0
  136. package/dist-lib/mud/text/wcwidth.d.ts +27 -22
  137. package/dist-lib/mud/timers/TimerEngine.d.ts +163 -11
  138. package/dist-lib/mud/timers/workerClock.d.ts +67 -0
  139. package/dist-lib/mud/triggers/TriggerEngine.d.ts +449 -47
  140. package/dist-lib/mud/triggers/legacyColorPatterns.d.ts +58 -0
  141. package/dist-lib/mud/triggers/pcre/Pcre2.d.ts +83 -1
  142. package/dist-lib/oauth-callback.html +94 -0
  143. package/dist-lib/pcre2Wasm.d.ts +54 -0
  144. package/dist-lib/pcre2Wasm.js +241 -0
  145. package/dist-lib/scripting/EngineHost.d.ts +45 -21
  146. package/dist-lib/scripting/IScriptingRuntime.d.ts +103 -27
  147. package/dist-lib/scripting/MxpFrameManager.d.ts +10 -1
  148. package/dist-lib/scripting/ScriptingAPI.d.ts +1030 -213
  149. package/dist-lib/scripting/ScriptingEngine.d.ts +727 -106
  150. package/dist-lib/scripting/StopwatchManager.d.ts +97 -36
  151. package/dist-lib/scripting/http/HttpService.d.ts +9 -1
  152. package/dist-lib/scripting/http/userUrl.d.ts +41 -0
  153. package/dist-lib/scripting/lua/LuaRuntime.d.ts +352 -77
  154. package/dist-lib/scripting/lua/argContracts.d.ts +71 -0
  155. package/dist-lib/scripting/lua/bindings/automation.d.ts +1 -1
  156. package/dist-lib/scripting/lua/bindings/commands.d.ts +13 -0
  157. package/dist-lib/scripting/lua/bindings/context.d.ts +20 -2
  158. package/dist-lib/scripting/lua/bindings/diagnostics.d.ts +1 -1
  159. package/dist-lib/scripting/lua/bindings/map.d.ts +1 -1
  160. package/dist-lib/scripting/lua/bindings/media.d.ts +2 -2
  161. package/dist-lib/scripting/lua/bindings/output.d.ts +1 -1
  162. package/dist-lib/scripting/lua/bindings/session.d.ts +2 -2
  163. package/dist-lib/scripting/lua/bindings/textEdit.d.ts +1 -1
  164. package/dist-lib/scripting/lua/bindings/userWindows.d.ts +1 -1
  165. package/dist-lib/scripting/lua/byteArmor.d.ts +36 -0
  166. package/dist-lib/scripting/lua/imageSize.d.ts +7 -0
  167. package/dist-lib/scripting/lua/rex.d.ts +4 -2
  168. package/dist-lib/scripting/lua/sqlRowEncoder.d.ts +6 -1
  169. package/dist-lib/scripting/lua/utf8CaseMap.d.ts +1 -0
  170. package/dist-lib/scripting/lua/utf8Patterns.d.ts +21 -1
  171. package/dist-lib/scripting/lua/wellFormedStrings.d.ts +40 -0
  172. package/dist-lib/scripting/lua/yajl.d.ts +43 -5
  173. package/dist-lib/scripting/profilesPresence.d.ts +20 -2
  174. package/dist-lib/scripting/vfs/ProfileVFS.d.ts +164 -10
  175. package/dist-lib/scripting/vfs/fsErrors.d.ts +28 -0
  176. package/dist-lib/scripting/vfs/idbCommit.d.ts +20 -0
  177. package/dist-lib/storage/appStore.d.ts +24 -9
  178. package/dist-lib/storage/hooks.d.ts +5 -1
  179. package/dist-lib/storage/index.d.ts +2 -2
  180. package/dist-lib/storage/mapStorage.d.ts +2 -0
  181. package/dist-lib/storage/persistentStorage.d.ts +3 -1
  182. package/dist-lib/storage/profileStorage.d.ts +15 -0
  183. package/dist-lib/storage/profileVfsData.d.ts +3 -3
  184. package/dist-lib/storage/schema.d.ts +512 -40
  185. package/dist-lib/storage/storageMigration.d.ts +82 -0
  186. package/dist-lib/storage-g5V1b-c1.js +2039 -0
  187. package/dist-lib/styles.css +1 -1
  188. package/dist-lib/ui/AboutModal.d.ts +1 -1
  189. package/dist-lib/ui/BrandLoginFields.d.ts +1 -1
  190. package/dist-lib/ui/BrowserSignInModal.d.ts +23 -0
  191. package/dist-lib/ui/CmdLineMenuRegistry.d.ts +14 -5
  192. package/dist-lib/ui/CommandBar.d.ts +8 -8
  193. package/dist-lib/ui/ConnectionFormModal.d.ts +20 -1
  194. package/dist-lib/ui/ConnectionScreen.d.ts +9 -1
  195. package/dist-lib/ui/GameLinkPrompt.d.ts +28 -0
  196. package/dist-lib/ui/HelpModal.d.ts +5 -1
  197. package/dist-lib/ui/MapSymbolUsageModal.d.ts +32 -0
  198. package/dist-lib/ui/MouseEventRegistry.d.ts +31 -4
  199. package/dist-lib/ui/NotepadModal.d.ts +22 -0
  200. package/dist-lib/ui/ResizableModal.d.ts +16 -1
  201. package/dist-lib/ui/SettingsModal.d.ts +10 -1
  202. package/dist-lib/ui/TlsAlertBanner.d.ts +3 -1
  203. package/dist-lib/ui/Toolbar.d.ts +22 -1
  204. package/dist-lib/ui/VaultManageButton.d.ts +10 -5
  205. package/dist-lib/ui/VaultModal.d.ts +3 -0
  206. package/dist-lib/ui/buttons/ButtonsBar.d.ts +3 -1
  207. package/dist-lib/ui/buttons/inactiveButtons.d.ts +25 -0
  208. package/dist-lib/ui/cmdline/CommandLineManager.d.ts +19 -0
  209. package/dist-lib/ui/cmdline/plainText.d.ts +16 -0
  210. package/dist-lib/ui/cmdline/subCommandLine.d.ts +78 -0
  211. package/dist-lib/ui/cmdline/useCmdLineSelection.d.ts +26 -0
  212. package/dist-lib/ui/cmdline/useSubCommandLineKeys.d.ts +33 -0
  213. package/dist-lib/ui/codemirror/lineParagraphMarks.d.ts +19 -0
  214. package/dist-lib/ui/codemirror/luaHover.d.ts +7 -0
  215. package/dist-lib/ui/codemirror/options.d.ts +33 -0
  216. package/dist-lib/ui/codemirror/theme.d.ts +29 -5
  217. package/dist-lib/ui/commands/addonCommands.d.ts +134 -0
  218. package/dist-lib/ui/commands/appShortcuts.d.ts +86 -0
  219. package/dist-lib/ui/commands/hostCommands.d.ts +88 -0
  220. package/dist-lib/ui/commands/keyMatch.d.ts +20 -0
  221. package/dist-lib/ui/commands/keySequence.d.ts +57 -0
  222. package/dist-lib/ui/components/ContextMenu.d.ts +21 -1
  223. package/dist-lib/ui/components/FontPicker.d.ts +5 -1
  224. package/dist-lib/ui/components/useModalFocus.d.ts +13 -1
  225. package/dist-lib/ui/helpTopics.d.ts +15 -0
  226. package/dist-lib/ui/labels/LabelManager.d.ts +172 -9
  227. package/dist-lib/ui/labels/LabelOverlay.d.ts +19 -0
  228. package/dist-lib/ui/labels/backgroundImageSize.d.ts +19 -0
  229. package/dist-lib/ui/labels/labelModel.d.ts +64 -0
  230. package/dist-lib/ui/labels/qColor.d.ts +13 -0
  231. package/dist-lib/ui/labels/qtCss.d.ts +12 -4
  232. package/dist-lib/ui/landmarks.d.ts +9 -0
  233. package/dist-lib/ui/launcher/ActionMenu.d.ts +19 -0
  234. package/dist-lib/ui/launcher/GameDetails.d.ts +21 -0
  235. package/dist-lib/ui/launcher/GameSection.d.ts +18 -0
  236. package/dist-lib/ui/launcher/LauncherSearch.d.ts +23 -0
  237. package/dist-lib/ui/launcher/ProfileArt.d.ts +20 -0
  238. package/dist-lib/ui/launcher/ProfileSection.d.ts +43 -0
  239. package/dist-lib/ui/launcher/launcherModel.d.ts +72 -0
  240. package/dist-lib/ui/layout/overlayLayerOrder.d.ts +2 -2
  241. package/dist-lib/ui/menu/MenuBar.d.ts +31 -0
  242. package/dist-lib/ui/menu/SplitButton.d.ts +39 -0
  243. package/dist-lib/ui/menu/anchoredPopup.d.ts +74 -0
  244. package/dist-lib/ui/menu/appMenus.d.ts +65 -0
  245. package/dist-lib/ui/menu/menuModel.d.ts +88 -0
  246. package/dist-lib/ui/menu/toolbarModel.d.ts +56 -0
  247. package/dist-lib/ui/notepad.d.ts +76 -0
  248. package/dist-lib/ui/openSignInPage.d.ts +14 -0
  249. package/dist-lib/ui/output/OutputContextMenu.d.ts +14 -1
  250. package/dist-lib/ui/output/OutputRenderer.d.ts +5 -0
  251. package/dist-lib/ui/output/OutputSearchBar.d.ts +5 -1
  252. package/dist-lib/ui/output/StickyOutputPanel.d.ts +17 -3
  253. package/dist-lib/ui/output/TextAnalyzerModal.d.ts +25 -0
  254. package/dist-lib/ui/output/caretMode.d.ts +3 -2
  255. package/dist-lib/ui/output/clearSplit.d.ts +11 -0
  256. package/dist-lib/ui/output/outputCopy.d.ts +41 -2
  257. package/dist-lib/ui/output/outputRows.d.ts +43 -0
  258. package/dist-lib/ui/output/selectionGesture.d.ts +35 -0
  259. package/dist-lib/ui/output/wordSelection.d.ts +33 -0
  260. package/dist-lib/ui/search/matcher.d.ts +14 -4
  261. package/dist-lib/ui/settings/SettingsShell.d.ts +91 -0
  262. package/dist-lib/ui/settings/ShortcutEditor.d.ts +13 -0
  263. package/dist-lib/ui/sound/SoundManager.d.ts +210 -44
  264. package/dist-lib/ui/sound/closedCaption.d.ts +4 -1
  265. package/dist-lib/ui/sound/mediaDirection.d.ts +35 -0
  266. package/dist-lib/ui/tabCompletion.d.ts +53 -0
  267. package/dist-lib/ui/textedit/TextEditManager.d.ts +11 -2
  268. package/dist-lib/ui/useOpenProfiles.d.ts +1 -1
  269. package/dist-lib/ui/video/VideoManager.d.ts +7 -0
  270. package/dist-lib/ui/windows/WindowManager.d.ts +452 -37
  271. package/dist-lib/ui/windows/panels/ScriptEditorPanel.d.ts +14 -0
  272. package/dist-lib/ui/windows/panels/ScriptSearch.d.ts +6 -1
  273. package/dist-lib/ui/windows/panels/TextPanel.d.ts +4 -1
  274. package/dist-lib/ui/windows/panels/VariablesView.d.ts +37 -7
  275. package/dist-lib/ui/windows/panels/WindowCmdLine.d.ts +4 -2
  276. package/dist-lib/ui/windows/panels/aliasLoop.d.ts +24 -0
  277. package/dist-lib/ui/windows/panels/editorClipboard.d.ts +45 -0
  278. package/dist-lib/ui/windows/panels/editorUndo.d.ts +79 -0
  279. package/dist-lib/ui/windows/panels/mapAreaChange.d.ts +10 -0
  280. package/dist-lib/utils/appShellCache.d.ts +25 -0
  281. package/dist-lib/utils/fontFamilyName.d.ts +13 -0
  282. package/dist-lib/utils/fontLoader.d.ts +31 -0
  283. package/dist-lib/utils/formatBytes.d.ts +4 -0
  284. package/dist-lib/utils/mustBeOneOf.d.ts +9 -0
  285. package/dist-lib/utils/profileLock.d.ts +1 -1
  286. package/dist-lib/utils/systemTheme.d.ts +24 -0
  287. package/dist-lib/utils/timeZone.d.ts +10 -0
  288. package/dist-lib/vault/CredentialVault.d.ts +51 -5
  289. package/dist-lib/vault/deviceUnlock.d.ts +47 -0
  290. package/dist-lib/vault/vaultAccess.d.ts +24 -2
  291. package/dist-lib/vault/vaultHelpTopic.d.ts +9 -0
  292. package/dist-lib/vault/vaultRecord.d.ts +33 -1
  293. package/dist-lib/vfs-sw.js +220 -11
  294. package/dist-lib/vite.d.ts +1 -1
  295. package/dist-lib/vite.js +66 -43
  296. package/package.json +23 -15
  297. package/dist-lib/assets/mapParser.worker-t-3rd1zR.js +0 -9
  298. package/dist-lib/mud/connection/PingTracker.d.ts +0 -41
  299. package/dist-lib/ui/BundledGameGrid.d.ts +0 -21
  300. package/dist-lib/ui/ConnectionGrid.d.ts +0 -21
  301. package/dist-lib/ui/bufferWords.d.ts +0 -38
@@ -3,13 +3,14 @@ import type { LogFormat } from '../logging/SessionLogger';
3
3
  import type { AliasEngine } from '../mud/aliases/AliasEngine';
4
4
  import { TriggerEngine } from '../mud/triggers/TriggerEngine';
5
5
  import type { TimerEngine } from '../mud/timers/TimerEngine';
6
- import type { KeyEngine } from '../mud/keybindings/KeyEngine';
6
+ import type { KeyEngine, KeyNode } from '../mud/keybindings/KeyEngine';
7
7
  import type { ButtonNode, ScriptNode } from '../storage/schema';
8
8
  import { type InstallOutcome } from './ScriptingAPI';
9
9
  import { type EngineHost, type TempComplexTriggerSpec } from './EngineHost';
10
10
  import { ItemIdSequence } from '../mud/ItemIdSequence';
11
- import type { LuaGlobalEntry } from './IScriptingRuntime';
11
+ import type { LuaGlobalEntry, VariableEdit } from './IScriptingRuntime';
12
12
  import { ProfileVFS } from './vfs/ProfileVFS';
13
+ import type { MudletImportResult } from '../import/mudletXmlImport';
13
14
  import type { PackageManifest } from '../storage/schema';
14
15
  export declare class ScriptingEngine implements EngineHost {
15
16
  private readonly session;
@@ -23,11 +24,7 @@ export declare class ScriptingEngine implements EngineHost {
23
24
  private readonly api;
24
25
  private promptPending;
25
26
  private mudCarryState;
26
- private gmcpNegotiated;
27
- private msdpNegotiated;
28
- private msspNegotiated;
29
- private mnesNegotiated;
30
- private mxpNegotiated;
27
+ private readonly enabledProtocols;
31
28
  /** True once MXP (telnet option 91) has been negotiated on the live
32
29
  * connection. Gates in-band MXP markup parsing in processFlushBatch so
33
30
  * non-MXP MUDs (where `<grin>` is literal text) are untouched. Reset on
@@ -38,22 +35,25 @@ export declare class ScriptingEngine implements EngineHost {
38
35
  * script can drive MXP markup through feedTriggers on a profile that never
39
36
  * negotiated it. Does NOT enable the handshake replies. */
40
37
  forceMxpProcessorOn: boolean;
41
- /** Whether MXP `<SUPPORTS>`/`<VERSION>` handshake replies may be sent. Only
42
- * true when MXP was started via the telnet option-91 handshake — an
43
- * in-band-detected server's inbound MXP isn't confirmed, so we'd otherwise
44
- * spam it with text it reads as invalid commands. */
45
- private mxpHandshakeEnabled;
38
+ /** cTelnet's `enableMXP`: the game switched MXP on (WILL, DO or a bare
39
+ * subnegotiation) or it was auto-enabled, and has not turned it off. */
40
+ private telnetMxpEnabled;
41
+ /** cTelnet's `mMxpAutoEnabled`: MXP is on because the auto-detect turned it
42
+ * on, so the game switching it on properly starts it afresh in open mode. */
43
+ private mxpAutoEnabled;
44
+ /** Mudlet's TMxpClient::mMxpEvents — element uses the parser has read but
45
+ * not yet published, drained at the end of processFlushBatch. */
46
+ private readonly mxpEventQueue;
46
47
  /** Per-session OSC 8 preset registry (`preset:NAME` definitions). Shared
47
48
  * between the MXP parser and the plain-ANSI render path so a preset defined
48
49
  * in either mode resolves in both. */
49
50
  private readonly osc8Presets;
50
51
  /** Drives expire-on-event OSC 8 visibility links (conceal on the next user
51
- * input / prompt / output after they're clicked). Scans the live output. */
52
+ * input / prompt / output after they're clicked) within the live output. */
52
53
  private readonly visibility;
53
54
  /** Per-session MXP parser. The send callback carries the in-band
54
- * `<SUPPORTS>`/`<VERSION>` handshake replies (gated on
55
- * `mxpHandshakeEnabled`); `api` is read lazily at call time so this
56
- * initializer is safe before the constructor body runs. */
55
+ * `<SUPPORTS>`/`<VERSION>` answers; `api` is read lazily at call time so
56
+ * this initializer is safe before the constructor body runs. */
57
57
  private readonly mxp;
58
58
  private vfs;
59
59
  private readonly runtimeReady;
@@ -67,6 +67,13 @@ export declare class ScriptingEngine implements EngineHost {
67
67
  private triggersReady;
68
68
  private triggersDirty;
69
69
  private prevScripts;
70
+ private profileScriptsCompiled;
71
+ private readonly scriptHandlerState;
72
+ private readonly failedScripts;
73
+ private readonly scriptLoadErrors;
74
+ private scriptCompileSeq;
75
+ private readonly scriptCompiledAt;
76
+ private compiledThisLoad;
70
77
  private resetting;
71
78
  private disposed;
72
79
  private moduleSyncTimers;
@@ -78,13 +85,25 @@ export declare class ScriptingEngine implements EngineHost {
78
85
  private mudletSaveName;
79
86
  private mspBaseUrl?;
80
87
  private gmcpMediaDefaultUrl;
88
+ private readonly gmcpMediaDownloads;
81
89
  private exitFired;
82
- private readonly beforeUnload;
90
+ private readonly onPageHide;
91
+ private readonly onPageShow;
83
92
  private uuidToNumericId;
84
93
  /** The profile's single item-id sequence, shared with every engine and with
85
94
  * the Lua runtime's temporary items — see {@link ItemIdSequence}. */
86
95
  readonly itemIds: ItemIdSequence;
87
- private numericIdFor;
96
+ /**
97
+ * The number Lua sees for a store node, allocating one on first sight.
98
+ *
99
+ * Public because the editor's "Show Items' ID number" shows the same number:
100
+ * the whole point of that option is to read off the id you would then pass to
101
+ * `enableTrigger` or `killTimer`, so it has to be *this* id and not the store's
102
+ * UUID. Allocating on first sight matches Mudlet, whose own tooltip warns that
103
+ * an item's id "is constant during a session of the profile [but] may be
104
+ * different the next time the profile is loaded".
105
+ */
106
+ numericIdFor(uuid: string): number;
88
107
  /** Hand out the next item id. Backs the Lua runtime's temporary items, so a
89
108
  * temp and a permanent item can never collide on one number. */
90
109
  allocateItemId(): number;
@@ -130,6 +149,36 @@ export declare class ScriptingEngine implements EngineHost {
130
149
  * `_G`. Called once before the initial script load so handlers see their
131
150
  * persisted state, and again after a profile reset (fresh global table).
132
151
  */
152
+ /**
153
+ * Put a package's own `<VariablePackage>` globals into `_G` and onto the
154
+ * profile's save-list.
155
+ *
156
+ * A package may carry nothing else — a module of variables, fonts, images or
157
+ * a map loads completely and leaves every one of the six item units empty —
158
+ * so skipping these made such a package indistinguishable from one whose
159
+ * contents never loaded at all. They are not items: nothing tags them and an
160
+ * uninstall does not take them away, which is Mudlet's behaviour too.
161
+ */
162
+ private restorePackageVariables;
163
+ /**
164
+ * Load an installed package's `<VariablePackage>` globals: into `_G`, and
165
+ * onto the save-list. For the installs that commit in one step — the
166
+ * Package Manager, the repository and Client.GUI — which desktop reads the
167
+ * same way as a script's installPackage. Call before the package's items go
168
+ * into the store, so its scripts see the values as they load.
169
+ */
170
+ loadPackageVariables(data: MudletImportResult): void;
171
+ /**
172
+ * Put an installed package's `<VariablePackage>` globals on the profile's
173
+ * save-list.
174
+ *
175
+ * Desktop's `XMLimport::readVariable` reads a package's variables exactly as
176
+ * it reads the profile's own, so each one lands on `VarUnit`'s saved list
177
+ * and it — and any later change to it — survives a restart. Called once the
178
+ * install commits, so a refused one adds nothing; the store change schedules
179
+ * the profile-data save that captures their values.
180
+ */
181
+ private savePackageVariables;
133
182
  private restoreSavedVariables;
134
183
  /**
135
184
  * Snapshot the save-listed globals out of `_G` into the store, just before a
@@ -142,22 +191,44 @@ export declare class ScriptingEngine implements EngineHost {
142
191
  * Write the live store state back into a linked Mudlet folder's profile save.
143
192
  * Bases on the newest parseable save (so external Mudlet edits to Host/unknown
144
193
  * fields are preserved), replaces the automation + variable packages with
145
- * mudix's current data, and writes a Mudlet-style timestamped file in current/
194
+ * Mudlet Web's current data, and writes a Mudlet-style timestamped file in current/
146
195
  * — one per session, overwritten on subsequent saves (the overwrite is safe
147
196
  * now that the folder backend truncates). Mudlet loads the newest such file.
148
197
  */
149
198
  private writeBackLinkedProfile;
199
+ /**
200
+ * Write this client's server encoding, TLS and character name back to a
201
+ * linked Mudlet folder's own files for them (`encoding`, `ssl_tsl`,
202
+ * `login`), in desktop's format, so desktop connects the same way. Only a
203
+ * linked folder — a Mudlet Web profile that called saveProfile() has a
204
+ * current/ too, but no desktop reading these (#259) — and only files whose
205
+ * value changed (desktopProfileFileUpdates). Never the password.
206
+ */
207
+ private writeBackDesktopProfileFiles;
150
208
  /**
151
209
  * The profile as a Mudlet-format `<MudletPackage>` save: `baseXml` with its
152
210
  * automation and variable packages replaced by the live store state, and its
153
211
  * `<Host>` settings updated in place.
154
212
  *
155
- * Basing on an existing save is what keeps the ~130 `<Host>` fields mudix
213
+ * Basing on an existing save is what keeps the ~130 `<Host>` fields Mudlet Web
156
214
  * doesn't model — and any element it doesn't understand — from being dropped
157
- * on the way out. A profile with no save to base on gets the empty skeleton
158
- * below, so its `<Host>` carries only the settings mudix does model.
215
+ * on the way out. With no save to base on, a profile imported from Mudlet
216
+ * falls back to the `<Host>` retained at import; one born in Mudlet Web gets the
217
+ * empty skeleton, so its `<Host>` carries only the settings Mudlet Web does model.
159
218
  */
160
219
  private buildProfileXml;
220
+ /**
221
+ * The `<Host>` a save starts from when there's no `current/*.xml` to base
222
+ * on: the one retained when this profile was imported from Mudlet, else the
223
+ * empty skeleton — either way stamped with the connection's current identity
224
+ * and package set, which desktop's `Host::saveProfile` always writes (the
225
+ * retained copy still names them as they were at import).
226
+ *
227
+ * Only reached when there's no `current/*.xml` to base on, so it never
228
+ * displaces a linked folder's own save. Undefined without a VFS; the bare
229
+ * retained file (or nothing) when the connection record is gone.
230
+ */
231
+ private hostBaseXml;
161
232
  /**
162
233
  * The XML half of Mudlet `saveProfile([location [, saveName]])`: write this
163
234
  * profile out as a Mudlet-format save and answer with the full path written.
@@ -175,20 +246,45 @@ export declare class ScriptingEngine implements EngineHost {
175
246
  } | {
176
247
  ok: false;
177
248
  err: string;
249
+ path?: string;
178
250
  };
179
251
  /** `_G` entries for the Variables view (user globals nested, built-ins
180
252
  * flagged). Empty until the runtime is up. */
181
253
  listGlobals(): LuaGlobalEntry[];
254
+ /** Apply one Variables-view edit to `_G`. Returns null on success, or the
255
+ * reason it was refused — including there being no runtime to edit. */
256
+ editVariable(request: VariableEdit): string | null;
182
257
  /**
183
258
  * Write the current in-store nodes for a module back to its XML file on disk.
184
259
  * Used both by the auto-sync debounce and the "Sync to file" UI action.
185
260
  */
186
261
  syncModuleToFile(moduleName: string): Promise<void>;
187
262
  /**
188
- * Re-read a module's XML from disk and replace its tagged nodes in the store.
189
- * Pairs with the "Reload from file" UI action.
190
- */
191
- reloadModuleFromFile(moduleName: string): boolean;
263
+ * Mudlet `reloadModule(name)` — Host::reloadModule, for a script and for
264
+ * the editor's "Reload from file" alike. Answers like an install does:
265
+ * `{ ok: true, error }` with whatever in the module does not work, or
266
+ * `{ ok: false, error }` with why it was not reloaded.
267
+ *
268
+ * Two things are checked before anything else, so the module's items are
269
+ * untouched by either: that it is installed at all, and that the file it
270
+ * was installed from can still be read — the reload takes the module
271
+ * apart before reading that file back in, and a file that has gone would
272
+ * leave it listed with nothing in it. Only then is a reload asked for
273
+ * during a profile save put off until the save is over; the true answered
274
+ * now is all the caller hears, so how the reload went afterwards is said on
275
+ * the console.
276
+ */
277
+ reloadModuleFromFile(moduleName: string): InstallOutcome;
278
+ /** Whether the file a module was installed from is a file that reads —
279
+ * QFileInfo's isFile() && isReadable() — in the profile or under the
280
+ * read-only /lua/ namespace. */
281
+ private moduleFileReadable;
282
+ /** Reloads put off by a profile save, carried out once it is over. */
283
+ private readonly postponedReloads;
284
+ /** The end of a profile save: the reloads it held up are carried out now,
285
+ * and only the console is left to tell how they went. */
286
+ private runPostponedReloads;
287
+ private reloadModuleNow;
192
288
  /** Toggle a module's sync flag. Updates the manifest in the store. */
193
289
  setModuleSync(moduleName: string, sync: boolean): void;
194
290
  /** Read a module's sync flag. Returns false if the package isn't a module. */
@@ -202,7 +298,9 @@ export declare class ScriptingEngine implements EngineHost {
202
298
  setModulePriority(moduleName: string, priority: number): boolean;
203
299
  /** Read a module's load priority (default 0). Returns 0 for non-modules. */
204
300
  getModulePriority(moduleName: string): number;
205
- /** List installed module names. Order matches install order. */
301
+ /** List installed module names, in byte order by name — desktop keeps
302
+ * them in a QMap keyed by name (Host::mInstalledModules), so that is the
303
+ * order getModules() reports, not the order they were installed in. */
206
304
  getModuleNames(): string[];
207
305
  /**
208
306
  * Write every module flagged to sync back out to its own file.
@@ -236,12 +334,21 @@ export declare class ScriptingEngine implements EngineHost {
236
334
  * via setPackageInfo. Empty table when the package is unknown and nothing
237
335
  * was set for that name. */
238
336
  getPackageInfo(name: string): Record<string, string>;
239
- /** Mudlet `setPackageInfo(name, key, value)`. Records a custom info field.
240
- * Always succeeds (matches Mudlet, which sets the map unconditionally). */
241
- setPackageInfo(name: string, key: string, value: string): boolean;
337
+ /** Mudlet `setPackageInfo(name, key, value)`. Records a custom info field,
338
+ * answering why it would not, or null once it has
339
+ * (TLuaInterpreter::setPackageInfo). */
340
+ setPackageInfo(name: string, key: string, value: string): string | null;
242
341
  /** Mudlet `setModuleInfo(name, key, value)`. Records a custom info field
243
- * surfaced by getModuleInfo. Always succeeds. */
244
- setModuleInfo(name: string, key: string, value: string): boolean;
342
+ * surfaced by getModuleInfo; see {@link setPackageInfo}. */
343
+ setModuleInfo(name: string, key: string, value: string): string | null;
344
+ /**
345
+ * Only for something installed — one being read in counts, so its own
346
+ * scripts can still describe it. Filed for any other name, the details were
347
+ * there for whatever was installed under it later. And `mpackage` is the
348
+ * name it is installed under, so only that same name is accepted for it: a
349
+ * package without a config.lua has no details to start from.
350
+ */
351
+ private setInfoField;
245
352
  /**
246
353
  * Mudlet `getModulePath(name) → path`. Absolute VFS path of an installed
247
354
  * module's XML. Modules referencing a file outside the managed package dir
@@ -253,11 +360,10 @@ export declare class ScriptingEngine implements EngineHost {
253
360
  /**
254
361
  * Install a module from a path inside the profile VFS. Plain XML stays in
255
362
  * place (manifest holds the absolute VFS path). Zips/.mpackages extract into
256
- * the standard pkgDir. Raises sysInstall, sysInstallPackage and
257
- * sysInstallModule on success — sysInstallModule is the module-specific
258
- * counterpart to sysInstallPackage. This method is reached only via the
259
- * Lua `installModule()` binding, so it also raises Mudlet's
260
- * `sysLuaInstallModule` (name, fileName) for ported-script parity.
363
+ * the standard pkgDir. This method is reached only via the Lua
364
+ * `installModule()` binding, so on success it raises what desktop's
365
+ * ModuleFromScript install does: sysInstall and sysLuaInstallModule
366
+ * (name, fileName) — not sysInstallPackage or sysInstallModule.
261
367
  */
262
368
  installModuleFromPath(path: string): InstallOutcome;
263
369
  /**
@@ -279,17 +385,83 @@ export declare class ScriptingEngine implements EngineHost {
279
385
  flushPendingApplies(): void;
280
386
  private applyTimersFromStore;
281
387
  private applyKeybindingsFromStore;
388
+ /** What this engine last told the button bar cannot be active, so that
389
+ * destroy() takes back only its own answer. */
390
+ private publishedInactiveButtons;
391
+ /**
392
+ * Tell the button bar which buttons, toolbars and menus will not compile.
393
+ * Desktop's TAction::compileScript leaves such a one with `mOK_code` false
394
+ * and Tree::activate refuses it, so the toolbar builders leave it off —
395
+ * a toolbar or menu with its buttons — while its switch stays as it was.
396
+ */
397
+ private applyButtonsFromStore;
398
+ /**
399
+ * Run every active push-down button once, in its saved state, as desktop
400
+ * does while a profile loads: TToolBar/TEasyButtonBar::addActionButtons
401
+ * and fillMenu execute each push-down button (menus' too) when
402
+ * `mIsProfileLoadingSequence` is set, with the console's mButtonState set
403
+ * from the saved state first. That is how a state-restoring button script
404
+ * re-applies itself on start (mudlet-web#356). Plain buttons do not run.
405
+ */
406
+ private runPushDownButtonsAtLoad;
282
407
  /**
283
408
  * On profile open, warn about enabled keybindings the browser intercepts
284
409
  * above the page (Ctrl+T new tab, Ctrl+W close tab, F12 devtools, …). Native
285
410
  * Mudlet packages bind these freely, but in a browser they can never reach
286
- * mudix — the warning explains why they "do nothing". Page-level shortcuts
287
- * mudix can still capture (Ctrl+R, Ctrl+S, F5, …) are intentionally not
411
+ * Mudlet Web — the warning explains why they "do nothing". Page-level shortcuts
412
+ * Mudlet Web can still capture (Ctrl+R, Ctrl+S, F5, …) are intentionally not
288
413
  * flagged: they work while the client is focused, same as in Mudlet.
289
414
  * Fired once at load (not on every store change) so it can't spam the output.
290
415
  */
291
416
  private warnBrowserReservedKeybindings;
292
417
  private applyScriptsFromStore;
418
+ /**
419
+ * Mudlet-style module load priority: scripts owned by modules with a
420
+ * negative priority load before profile scripts; non-negative priorities
421
+ * load after. Within a priority bucket, original array order is preserved
422
+ * so existing trees stay deterministic. Profile-owned scripts (no
423
+ * packageName) are treated as priority 0. Equal priorities: the profile
424
+ * before its modules (its XML is read before any module installs), and
425
+ * modules by name among themselves.
426
+ */
427
+ private scriptLoadOrder;
428
+ /**
429
+ * ScriptUnit::compileAll at profile load. Desktop walks its live tree and
430
+ * asks each root whether it is active only when it reaches it, so a body
431
+ * that runs earlier can switch a later script on or off, replace its code
432
+ * or remove it, and the walk honours that. Here every step re-reads the
433
+ * store, and first takes in whatever the last body changed (handler
434
+ * activity, a body setScript replaced) — the store subscription is not
435
+ * attached yet on a first load, and the walk has to see the change before
436
+ * it moves on either way.
437
+ */
438
+ private compileProfileScripts;
439
+ /**
440
+ * Host::reportScriptsThatFailedToLoad: once the profile's scripts have run
441
+ * — at open, and again after a reset — one warning names every switched-on
442
+ * script whose body failed, in script-list order, so a broken script is
443
+ * not lost among the errors that scrolled past. Module scripts are left
444
+ * out, as on desktop: a module of positive priority runs its scripts only
445
+ * after this, so reporting the others would make the warning depend on a
446
+ * module's priority.
447
+ */
448
+ private reportScriptsThatFailedToLoad;
449
+ /** Whether the root `s` sits under is switched on — what compileAll asks
450
+ * of each root before compiling its subtree. */
451
+ private scriptRootActive;
452
+ /**
453
+ * Event-handler lists (Host::mEventHandlerMap). Every script that lists
454
+ * events is registered, enabled or not — desktop registers them as the XML
455
+ * is read and asks isActive() && ancestorsActive() only when an event comes
456
+ * (TScript::callEventHandler). isActive() wants the body to have compiled
457
+ * too, so a script that failed, or sits under one that did, is registered
458
+ * inactive. Registration order is load order: the profile's own tree
459
+ * first, then modules by priority, which install after it
460
+ * (mudlet::slot_connectionDialogueFinished). Only what changed since the
461
+ * last sync is sent.
462
+ */
463
+ private syncScriptHandlersFrom;
464
+ private syncScriptHandlers;
293
465
  /** Map of module name → priority. Profile (no packageName) is implicitly 0. */
294
466
  private modulePriorityMap;
295
467
  private initRuntime;
@@ -315,9 +487,6 @@ export declare class ScriptingEngine implements EngineHost {
315
487
  * `expandAlias(text, echo)` is exactly this function.
316
488
  */
317
489
  hostSend(text: string, echo?: boolean): void;
318
- /** Nesting depth of {@link hostSend} — see the runaway-alias note there. */
319
- private sendDepth;
320
- private static readonly MAX_SEND_DEPTH;
321
490
  /** Mudlet `expandAlias(text, echo)` — `Host::send` with both defaults, i.e.
322
491
  * "run this as though I had typed it". */
323
492
  expandAlias(text: string, echo: boolean): void;
@@ -325,11 +494,34 @@ export declare class ScriptingEngine implements EngineHost {
325
494
  requestReconnect(): boolean;
326
495
  /** Raise sysDataSendRequest; true means a handler called denyCurrentSend(). */
327
496
  dispatchSendRequest(text: string): boolean;
497
+ /**
498
+ * The refusal for installing something under a name the *other* kind is
499
+ * already using, or null when the name is free of it.
500
+ *
501
+ * A package and a module may not share one name. Uninstall removes items by
502
+ * name alone, so a name held both ways loses both halves' items whichever
503
+ * half is removed — the user uninstalls a package and a module's triggers
504
+ * and scripts go with it, unwarned. Each half also displaced the other from
505
+ * its own listing, so nothing in the UI revealed the collision first
506
+ * (issue #104).
507
+ *
508
+ * Desktop refuses both directions with these two sentences
509
+ * (`Host::installPackage`, Host.cpp:2567 and :2584) and deliberately lets a
510
+ * profile that already holds the combination go on loading — only a *fresh*
511
+ * install is turned away, or a profile saved before the check existed would
512
+ * become unopenable. Here that exemption needs no flag: reopening a profile
513
+ * replays its modules through `reloadModuleFromVfs`, which never reaches
514
+ * this, so only the install entry points below can be refused.
515
+ *
516
+ * Asked after the name is settled, never before: `config.lua` can rename an
517
+ * archive to anything at all, so the file's own name answers nothing.
518
+ */
519
+ crossKindInstallRefusal(name: string, installing: 'package' | 'module'): string | null;
328
520
  /** Names of every package installed in this profile. */
329
521
  getPackageNames(): string[];
330
522
  /** What the module's config.lua declared, with Lua-set overrides applied.
331
523
  * The same contract as getPackageInfo — see manifestInfoBase. This used to
332
- * hand back the whole manifest, so callers saw mudix's own bookkeeping
524
+ * hand back the whole manifest, so callers saw Mudlet Web's own bookkeeping
333
525
  * (installedAt, sourceFile, and latterly declaredInfo itself) alongside the
334
526
  * fields the module author actually wrote. */
335
527
  getModuleInfoRecord(name: string): Record<string, unknown> | null;
@@ -345,30 +537,87 @@ export declare class ScriptingEngine implements EngineHost {
345
537
  readFileBytes(path: string): Uint8Array | null;
346
538
  writeFileBytes(path: string, bytes: Uint8Array): boolean;
347
539
  configDirectory(): string | null;
348
- private createRuntime;
349
540
  /**
350
- * Tear down a script's event-handler registrations. Used when a script is
351
- * removed or transitions enabled→disabled so its handlers stop firing
352
- * before the next full runtime reload.
353
- *
354
- * Runs synchronously once the runtime is up so the store-subscription
355
- * pipeline (script removed → handlers gone) completes inside the same
356
- * tick as the store mutation. See attachToStore for the rationale.
357
- */
358
- unloadScript(scriptId: string): void;
541
+ * The VFS paths a media name may refer to, most likely first. An absolute
542
+ * path is taken as it stands (getMudletHomeDir().."/media/x.wav" is the
543
+ * common package idiom), falling back to reading it as profile-relative
544
+ * for the older "/media/x.wav" spelling. A relative name is looked up in
545
+ * the profile's media/ directory first, where Mudlet resolves it, then
546
+ * against the profile root ("media/x.wav" as packages have long written it).
547
+ */
548
+ private mediaPathCandidates;
549
+ /**
550
+ * The file a media name plays: the first of its {@link mediaPathCandidates}
551
+ * that exists, as a full VFS path. A `*` or `?` in the file name is a
552
+ * wildcard, as in Mudlet's TMedia, and plays one of the files it matches,
553
+ * picked at random. A URL is returned as it is; a name that matches no
554
+ * file is null, which the SoundManager refuses without listing it.
555
+ */
556
+ private resolveMediaPath;
557
+ /** Sound/video loader: absolute URLs hit the network; everything else is
558
+ * read from the mounted profile VFS (see {@link mediaPathCandidates}). */
559
+ private loadMediaBytes;
560
+ private createRuntime;
359
561
  /**
360
562
  * Raise sysInstall / sysInstallPackage. The caller is expected to have
361
563
  * just committed the package's items to the appStore — our subscription
362
564
  * loads the new scripts synchronously inside that commit, so by the time
363
565
  * this method runs the package's event handlers are already registered.
364
566
  */
365
- notifyPackageInstalled(packageName: string, fileName?: string): void;
567
+ notifyPackageInstalled(packageName: string, fileName?: string, problems?: string | null): void;
568
+ /** The half of an install every kind shares: apply the new items, register
569
+ * their fonts and raise the generic sysInstall. The caller raises the one
570
+ * detailed event that fits how the install was asked for. */
571
+ private notifyInstalled;
572
+ /** Everything an install does once its items are in, short of saying so:
573
+ * apply them and register the package's fonts. */
574
+ private finishInstall;
575
+ /** How many times each package or module has been removed — Host's
576
+ * mRemovalsOf. A reload's own removal is not counted: it puts the same
577
+ * module straight back. */
578
+ private readonly removalsOf;
579
+ private countRemoval;
580
+ /** A module whose XML broke before anything was read in has nothing
581
+ * running, so it is not announced (Host's moduleLoadedNothing). */
582
+ private moduleLoadedNothing;
583
+ /**
584
+ * Raise an install's sysInstall and then its detailed event on the next
585
+ * pass of the event loop, as Host::installPackage does (a zero-timer), so
586
+ * everything the install set up - its variables above all - is in place
587
+ * before a handler runs. An install undone before then is not announced,
588
+ * nor is the detailed event raised once a sysInstall handler has taken it
589
+ * away again: its errors would be stale by then.
590
+ */
591
+ private announceInstallLater;
592
+ /** Re-register every installed package's fonts on profile open. See the
593
+ * call site in `start()` and {@link registerPackageFonts}. */
594
+ private refreshInstalledPackageFonts;
595
+ /**
596
+ * Register the fonts one just-installed package ships — desktop's
597
+ * `Host::installPackageFonts` (Host.cpp:3513), called from `installPackage`
598
+ * at :2802. Without it a package's font unpacked correctly and was then
599
+ * never handed to the browser, so nothing in the profile could use it and
600
+ * nothing said why (issue #103).
601
+ *
602
+ * The faces are in `document.fonts` — so `getAvailableFonts()` lists them
603
+ * and `setFont` takes them — before this returns, which is before the
604
+ * caller raises sysInstall/sysInstallPackage: a package that sets its own
605
+ * font in its install handler finds it there, as on desktop (#438). Only
606
+ * the parse finishes later (`FontFace.load()` is async), and a font is not
607
+ * a reason to hold up an install that has otherwise succeeded — desktop's
608
+ * `loadFont` reports and carries on too.
609
+ *
610
+ * Failures reach the error log rather than the console, because a font that
611
+ * will not load is a defect in the package, which is exactly what the
612
+ * Errors tab is for.
613
+ */
614
+ private registerPackageFonts;
366
615
  /**
367
616
  * Raise sysUninstall / sysUninstallPackage. Call this BEFORE removing the
368
617
  * package's items from the store so the package's own handlers (and the
369
618
  * scripts they live in) are still loaded when the event fires.
370
619
  */
371
- notifyPackageUninstalled(packageName: string): void;
620
+ notifyPackageUninstalled(packageName: string, kind?: 'package' | 'module'): void;
372
621
  /**
373
622
  * Stage a File dropped on a window into the profile VFS, then raise Mudlet's
374
623
  * sysDropEvent(filepath, suffix, x, y, name) with the resulting VFS path. The
@@ -436,9 +685,10 @@ export declare class ScriptingEngine implements EngineHost {
436
685
  */
437
686
  private defaultMediaLocation;
438
687
  /**
439
- * Resolve a media `file` (+ optional base `url` directory) to a VFS-relative
440
- * path under `media/` the SoundManager loader can read, downloading and
441
- * caching it on a miss. Shared by MSP (`resolveMspMedia`) and the GMCP media
688
+ * Resolve a media `file` (+ optional base `url` directory) to its absolute
689
+ * VFS path under the profile's `media/` the SoundManager loader can read,
690
+ * downloading and caching it on a miss (raising sysDownloadDone /
691
+ * sysDownloadError for the download, as TMedia does). Shared by MSP (`resolveMspMedia`) and the GMCP media
442
692
  * protocol (`handleClientMedia`). The whole filename — including any
443
693
  * subdirectories — is appended to the base URL and mirrored under `media/`,
444
694
  * so the cache layout matches the server's. `..`/`.` segments are rejected
@@ -448,13 +698,32 @@ export declare class ScriptingEngine implements EngineHost {
448
698
  */
449
699
  private resolveMediaFile;
450
700
  /**
451
- * Handle a GMCP media message (`Client.Media.Play/Load/Stop/Default`).
701
+ * Handle a GMCP media message (`Client.Media.Play/Load/Stop/Pause/Default`).
452
702
  * Mirrors Mudlet's `TMedia` MediaProtocolGMCP. The payload is the already-
453
703
  * parsed JSON body; `action` is the lowercased segment after `Client.Media`
454
- * (defaulting to `play`, matching Mudlet's bare `Client.Media`). Server-
455
- * driven, so playback rides the `game` mute gate like MSP.
704
+ * (a bare `Client.Media` is Default, as in TMedia::parseGMCP). Server-
705
+ * driven, so playback rides the `game` mute gate like MSP, and a Stop or
706
+ * Pause reaches only server media — never what a script started.
456
707
  */
457
708
  private handleClientMedia;
709
+ /** Mudlet's `cTelnet::postMessage`: a client notice on the main console,
710
+ * written to the buffer as well as the renderer so getLines() and the
711
+ * cursor APIs see the line the player reads (see ScriptingAPI.postInfo). */
712
+ private postMainMessage;
713
+ /**
714
+ * A `Client.GUI` offer, after its gmcp table update. Mudlet
715
+ * (cTelnet::setGMCPVariables) ignores the whole message when the profile
716
+ * refuses server packages; otherwise it acts on the install, and then — if
717
+ * the game declined the built-in starter UI with `{"baseui": false}` —
718
+ * raises sysServerGuiInstalled with no package named, the same event an
719
+ * installed interface raises. The install's synchronous part (its
720
+ * "Downloading" notice) runs first, as it does on desktop; the download
721
+ * itself settles later.
722
+ */
723
+ private handleClientGui;
724
+ /** Mudlet's `mAcceptServerGUI` — the profile's `allowMudPackageInstall`,
725
+ * where undefined means allowed. */
726
+ private serverGuiAccepted;
458
727
  private handleClientGuiInstall;
459
728
  /** Guards against overlapping downloads — Mudlet TMap::mImportRunning. */
460
729
  private mapDownloadRunning;
@@ -466,6 +735,43 @@ export declare class ScriptingEngine implements EngineHost {
466
735
  * importer and everything else through the binary `.dat` reader.
467
736
  */
468
737
  downloadMap(remoteUrl?: string): Promise<boolean>;
738
+ /** The script whose body is running right now (Host's mRunningScript): its
739
+ * chunk name and the package or module it came with ('' for the profile). */
740
+ private runningScript;
741
+ /**
742
+ * Which package or module owns the code a Lua frame is running, '' for the
743
+ * profile's own — desktop's packageOfFrame, which addCommand asks so that a
744
+ * package's commands go with it.
745
+ *
746
+ * The running script's own body is its package's. Otherwise the chunk is
747
+ * whoever's items run under that chunk name, or whose folder the file lies
748
+ * in; when several do — a package script and a profile script may share a
749
+ * name — the running script's package still owns it if a main chunk of
750
+ * the same source calls this frame directly (a local function its body
751
+ * called), and anything else is the profile's: code a package merely runs
752
+ * for someone else is theirs.
753
+ */
754
+ packageOfCaller(source: string, isMain: boolean, calledFromMain: boolean): string;
755
+ /**
756
+ * The chunks of a package's items as they are removed, with the package
757
+ * that owned them, until the next pass of the event loop. Desktop takes a
758
+ * removed item out of the tree at once but frees it only once the pass
759
+ * that is running it is over, so code of the item that is still running -
760
+ * a trigger that uninstalled its own package, then placed a command - is
761
+ * still its package's.
762
+ */
763
+ private readonly removedChunkOwners;
764
+ private rememberOwnersOfRemovedItems;
765
+ private ownersOfChunk;
766
+ /**
767
+ * Lua `uninstallPackage(name)`: why it would not, or null once it has
768
+ * (TLuaInterpreter::uninstallPackage). Whether the package is installed is
769
+ * asked first — retrying one that is not never works, so a running save is
770
+ * not the reason to give for it — and an installed one is refused only
771
+ * while a profile save is running. A save a handler starts once the
772
+ * uninstall is under way is no reason to abandon it.
773
+ */
774
+ uninstallPackageFromScript(packageName: string): string | null;
469
775
  /**
470
776
  * Uninstall a previously installed package by name. Raises sysUninstallPackage
471
777
  * before the store removal so the package's own handlers can still run.
@@ -505,6 +811,63 @@ export declare class ScriptingEngine implements EngineHost {
505
811
  * Same batching as toggleTriggerByName: one set() collapses N matches into
506
812
  * a single subscription tick (and a single TimerEngine.loadPerm rebuild).
507
813
  */
814
+ /** Whether a profile save still counts as running: a second save is
815
+ * refused, and so is an uninstall, as Host::currentlySavingProfile()
816
+ * makes them. */
817
+ private profileSaveInFlight;
818
+ /** Which save the scheduled end below belongs to, so the end of one that
819
+ * was waited out cannot cut a later save short. */
820
+ private profileSaveGeneration;
821
+ /**
822
+ * Mark a profile save as running until the next pass of the event loop.
823
+ */
824
+ markProfileSaveInFlight(): void;
825
+ /**
826
+ * Host::waitForProfileSave for a script's install: desktop runs the event
827
+ * loop until the save's writes are done, delivering nothing but the save's
828
+ * own completions. Mudlet Web's save has already written everything by the
829
+ * time it counts as running (the VFS flush that follows only makes it
830
+ * durable, and later writes join it), so what is left to wait for is the
831
+ * window itself - ended here and now, so nothing else gets to run in the
832
+ * middle of the waiting script either.
833
+ */
834
+ private waitOutProfileSave;
835
+ private saveAfterPackageChangePending;
836
+ /**
837
+ * The profile save a package install or uninstall is followed by, put off
838
+ * to the next pass of the event loop (Host's mDeferredSaveTimer) so a batch
839
+ * of installs is not queued behind one save each — and again until no save
840
+ * or install is running, as one started under an install would hold its
841
+ * scripts up. Asked for twice, it saves once.
842
+ *
843
+ * Nothing is waiting on an answer, so a save that cannot be written is said
844
+ * on the console (Host::saveProfileReportingFailure); one turned away
845
+ * because another is running names no file and is let be.
846
+ */
847
+ private saveAfterPackageChange;
848
+ /** Runs a package's config.lua the way Mudlet does — in an environment with
849
+ * nothing in it — so a manifest that would raise is read as raising here
850
+ * too. Bound rather than a method reference so the installer can hold it. */
851
+ private get readPackageConfig();
852
+ /**
853
+ * A crash part-way through an install leaves the folder it was unpacking
854
+ * into, a "mudlet-installing-" one marked ".mudlet-unpacking"; the next
855
+ * install of an archive clears it away (Host::installPackage). One
856
+ * holding files an install had moved out of the way (".mudlet-replaced")
857
+ * is all that is left of them, so it is kept and its place said instead.
858
+ * A package or module that is itself called that is left alone.
859
+ */
860
+ private clearAwayCrashedUnpacking;
861
+ /** Said when a package's XML would not read, once per file that broke,
862
+ * with the reader's reason — Host::installPackage's "Failed to load
863
+ * package/module" warning. Only modules were ever asked whether their
864
+ * contents loaded, so a package installed to silence. */
865
+ private announceUnreadableContents;
866
+ /** What a lost manifest costs, said once, where the player will see it: the
867
+ * package installed under the archive's own name and filed no details, so a
868
+ * name-based uninstall, a repository update and anything depending on it
869
+ * all stop matching with nothing to go on. */
870
+ private announceLostManifest;
508
871
  toggleTimerByName(name: string, enabled: boolean): boolean;
509
872
  /**
510
873
  * Toggle aliases' enabled flag by name (Mudlet enableAlias/disableAlias).
@@ -530,13 +893,12 @@ export declare class ScriptingEngine implements EngineHost {
530
893
  /** The saved keybinding carrying this numeric id, or null. Lets getKeyCode
531
894
  * answer for a permanent key by the id permKey handed back, not just by
532
895
  * name — the key engine only indexes permanent keys by name. */
533
- keyNodeByNumericId(numericId: number): {
534
- key: string;
535
- modifiers: string[];
536
- } | null;
537
- /** enable/disable a script-created temp trigger or alias by numeric id.
538
- * Those live in the Lua runtime, not the saved tree. */
539
- setTempItemEnabled(id: number, enabled: boolean): boolean;
896
+ savedKeyNode(idOrName: number | string): KeyNode | null;
897
+ /** Host::setForceMXPProcessorOn and the slot its signal drives: forcing on a
898
+ * processor that is off turns it on locked to secure mode (IRE-style games
899
+ * use secure tags without sending mode switches), while one the game
900
+ * already had on keeps its mode. Turning it off leaves the modes alone and
901
+ * stops the processor unless the game has MXP on. */
540
902
  setForceMxpProcessorOn(on: boolean): void;
541
903
  /** Mudlet `cTelnet::autoEnableMXPProcessor`. Runs when MXP started from an
542
904
  * in-band `ESC[<n>z` rather than a telnet option-91 handshake: such servers
@@ -551,6 +913,24 @@ export declare class ScriptingEngine implements EngineHost {
551
913
  * server re-announcing MXP after e.g. `config mxp on`): re-apply the lock,
552
914
  * but stay silent — Mudlet returns before its postMessage there. */
553
915
  private autoEnableMxpProcessor;
916
+ /**
917
+ * The temporary half of a kind's one tree, as the lookups below read it, or
918
+ * null for a kind whose temporaries are not yet held this way.
919
+ *
920
+ * Desktop keeps temporary and permanent items of a kind in one tree and
921
+ * one name table, so exists/isActive/findItems/ancestors see both; here
922
+ * the permanent half is the store and the temporary half is the engine.
923
+ */
924
+ private tempTree;
925
+ /**
926
+ * The temporary item a store node hangs off, when that item is killed or
927
+ * already freed — desktop's `*Unit::pendingDeletion`, which walks the item
928
+ * and every ancestor, so a killed parent takes its whole subtree out of
929
+ * exists/isActive/findItems until the cleanup frees it for good.
930
+ */
931
+ private isPendingDeletion;
932
+ /** `list` without the nodes {@link isPendingDeletion} rules out. */
933
+ private liveNodes;
554
934
  existsByName(nameOrId: string | number, type: string): number;
555
935
  /**
556
936
  * Mudlet `isActive(nameOrId, type [, checkAncestors])`. Returns the count of
@@ -567,6 +947,25 @@ export declare class ScriptingEngine implements EngineHost {
567
947
  */
568
948
  isKnownItemType(type: string): boolean;
569
949
  private nodeListForType;
950
+ /**
951
+ * Give every item saved with this profile its number, at load, before a
952
+ * script can run and claim one.
953
+ *
954
+ * {@link numericIdFor} allocates on first sight, which is enough for the Lua
955
+ * API on its own — but "first sight" then depends on what a script happened
956
+ * to touch, and (since the editor's "Show Items' ID number" reads the same
957
+ * ids) on whether the editor had been opened. Desktop has no such ambiguity:
958
+ * `TTrigger`, `TAlias` and the rest take their id as they are constructed
959
+ * from the profile XML, so the profile's own items always hold the first
960
+ * numbers and a temporary one created later carries on from there. Doing the
961
+ * same here costs one pass over the tree and makes the ids people read off
962
+ * the editor the ones they would have got anyway.
963
+ *
964
+ * Same order as the store, which is the order the profile was written in.
965
+ * Groups are numbered too: desktop gives a group an id like any other item,
966
+ * and `ancestors()` already reports them by number.
967
+ */
968
+ private assignSavedItemIds;
570
969
  private nodeTypeLabel;
571
970
  /**
572
971
  * Mudlet `ancestors(id, type)`. Walks from the item's immediate parent up to
@@ -599,18 +998,18 @@ export declare class ScriptingEngine implements EngineHost {
599
998
  * Mudlet `getProfileStats()`. Counts of total/active items per family plus
600
999
  * the trigger pattern tally. Temporary items (tempTimer/tempAlias/... ) are
601
1000
  * not kept in the persisted node tree but live in the per-family engines, so
602
- * their counts come from those engines: `temp` is the live temp count and
603
- * is folded into `total`/`active` (a live temp is always active), matching
604
- * Mudlet's report. Scripts have no temp form. There's no animated-GIF
605
- * tracker, so `gifs` is always zero.
1001
+ * their counts come from those engines: `temp` is the temp count and is
1002
+ * folded into `total`/`active`, matching Mudlet's report. Desktop's
1003
+ * assembleReport walks the live root lists unfiltered, so a killed item —
1004
+ * and whatever hangs under it — still counts until the cleanup frees it.
1005
+ * Scripts have no temp form.
606
1006
  */
607
1007
  getProfileStats(): Record<string, unknown>;
608
1008
  /**
609
1009
  * Mudlet `permScript(name, parent, luaCode)`. Creates a saved Lua script
610
1010
  * named `name` under the script group `parent` (empty = root). Returns the
611
1011
  * new script's id on success, -1 if `parent` is given but no script group
612
- * with that name exists. The store subscription loads the script's
613
- * handlers synchronously inside the addScript commit.
1012
+ * with that name exists. The body runs once, before this returns.
614
1013
  */
615
1014
  createPermScript(name: string, parent: string, code: string): number;
616
1015
  /**
@@ -647,6 +1046,15 @@ export declare class ScriptingEngine implements EngineHost {
647
1046
  */
648
1047
  createPermPromptTrigger(name: string, parent: string, code: string): number;
649
1048
  private createPermTrigger;
1049
+ /**
1050
+ * The parent a `perm*(name, parent, …)` call names: the NEWEST item of the
1051
+ * kind carrying that name, temporary or permanent — desktop's findTrigger /
1052
+ * findFirstAlias / findFirstTimer / findFirstKey look both up in the one
1053
+ * name table, newest first, with no folder and no pending-deletion check.
1054
+ * A temporary parent is answered as its temp parent ref (see
1055
+ * TEMP_PARENT_PREFIX in schema.ts); null when nothing carries the name.
1056
+ */
1057
+ private resolvePermParent;
650
1058
  /**
651
1059
  * Mudlet `tempComplexRegexTrigger(...)`. A session-scoped trigger with
652
1060
  * everything a permanent one can have — an AND chain across lines, a filter
@@ -663,17 +1071,30 @@ export declare class ScriptingEngine implements EngineHost {
663
1071
  */
664
1072
  createTempComplexTrigger(spec: TempComplexTriggerSpec): number;
665
1073
  /**
666
- * Remove a temporary trigger by the numeric id `tempComplexRegexTrigger`
667
- * handed the script. False when that id names no temporary trigger — a
668
- * permanent one is refused, as Mudlet's killTrigger refuses it.
1074
+ * Remove a temporary trigger node — an isTempTrigger="yes" item a package
1075
+ * XML brought in — by its numeric id. False when that id names no such
1076
+ * node — a permanent one is refused, as Mudlet's killTrigger refuses it.
669
1077
  */
670
1078
  removeTemporaryTriggerById(id: number): boolean;
671
1079
  /** Remove a trigger and everything under it. A child outlives its parent
672
1080
  * nowhere in the tree, and a permanent trigger parented to a temporary one
673
1081
  * goes with it — which is the only way it could have been reached. */
674
1082
  private removeTriggerSubtree;
675
- /** The root ancestor of a trigger node — what a lineage is recorded against. */
676
- private rootTriggerOf;
1083
+ /**
1084
+ * Remove from the store the permanent items whose temporary parent has been
1085
+ * freed. Desktop deletes an item's children with it (~TTrigger →
1086
+ * deleteChildren), temporary or not, so the cleanup that frees a killed
1087
+ * temporary item frees the permanent subtree a script hung under it.
1088
+ * The engines report which parents went (takeOrphanedParents); until this
1089
+ * runs nothing reaches those nodes, and the lookups count them as gone.
1090
+ */
1091
+ private removeOrphanedTempChildren;
1092
+ /** Remove every permanent item hanging off a temporary one, of every kind. */
1093
+ private dropTempParentedNodes;
1094
+ /** Remove every store node of `type` hanging (at any depth) off one of the
1095
+ * temp parent refs in `refs`, or off any temp parent at all when `refs`
1096
+ * is null. */
1097
+ private removeSubtreesUnder;
677
1098
  /**
678
1099
  * Mudlet `permAlias(name, parent, regex, luaCode)`. Creates a saved alias
679
1100
  * named `name` under the alias group `parent` (empty = root). The pattern
@@ -684,7 +1105,7 @@ export declare class ScriptingEngine implements EngineHost {
684
1105
  createPermAlias(name: string, parent: string, pattern: string, code: string): number;
685
1106
  /**
686
1107
  * Mudlet `permTimer(name, parent, seconds, luaCode)`. Creates a saved
687
- * one-shot timer under the timer group `parent` (empty = root). Returns
1108
+ * repeating timer under the timer group `parent` (empty = root). Returns
688
1109
  * the new timer id, or -1 if `parent` is non-empty but no timer group of
689
1110
  * that name exists.
690
1111
  */
@@ -699,43 +1120,71 @@ export declare class ScriptingEngine implements EngineHost {
699
1120
  */
700
1121
  createPermKey(name: string, parent: string, modifier: number, key: string | number, code: string): number;
701
1122
  /**
702
- * Mudlet `tempButton(toolbar, name, code[, orientation])`. Appends a
703
- * transient button under an existing toolbar group. Returns the new id, or
704
- * -1 when no toolbar of that name exists. `orientation` is round-tripped
1123
+ * Mudlet `tempButton(toolbar, name, orientation)`. Appends a transient
1124
+ * button under an existing toolbar group, with no command and no script:
1125
+ * TLuaInterpreter::tempButton gives it an empty one, and its third
1126
+ * argument is the orientation. Returns the new id, or a refusal code:
1127
+ * -1 when nothing has the toolbar's name, -2 when what has it is a plain
1128
+ * button (desktop's findAction(toolbar) takes the first action of that
1129
+ * name and refuses one that is not a folder, as a button under a button
1130
+ * never reaches a toolbar), -3 when a button or toolbar already has the
1131
+ * name — desktop refuses a duplicate rather than adding a second button,
1132
+ * so a script that makes its buttons on every load does not pile them up
1133
+ * (mudlet-web#238). The Lua wrapper turns each into nil and desktop's
1134
+ * message. `orientation` is round-tripped
705
1135
  * onto the leaf for parity with Mudlet — the renderer doesn't use it at the
706
1136
  * leaf, but ports that read it back via the store get a stable value.
707
1137
  */
708
- createTempButton(toolbar: string, name: string, code: string, _orientation: number): number;
1138
+ createTempButton(toolbar: string, name: string, _orientation: number): number;
709
1139
  /**
710
1140
  * Mudlet `tempButtonToolbar(name [, orientation [, location]])`. Creates a
711
1141
  * transient toolbar (ButtonNode group). `orientation`: 0=horizontal,
712
1142
  * 1=vertical. `location`: 0=top, 1=bottom, 2=left, 3=right, 4=floating.
713
- * Returns -1 when a toolbar group of that name already exists.
1143
+ * Returns -1 when a toolbar or button of that name already exists —
1144
+ * desktop's findAction(name) is not limited to toolbars.
714
1145
  */
715
1146
  createTempButtonToolbar(name: string, orientation: number, location: number): number;
716
1147
  /** Mudlet `setButtonState(name, state)`. Flips the buttonState on the named
717
1148
  * two-state button. */
1149
+ /**
1150
+ * The button the button-state functions mean: a name finds the first
1151
+ * button (not toolbar) called that, a number is an item ID — the one
1152
+ * findItems() handed out, which Mudlet's getAction(id) resolves whatever
1153
+ * the item is, so a toolbar found by ID is simply not a push-down button.
1154
+ */
1155
+ private findButton;
718
1156
  /**
719
1157
  * What `name` refers to, so the Lua side can say which of Mudlet's several
720
1158
  * refusals applies: no such button, or a button that has no state to set
721
1159
  * because it is not a two-state one.
722
1160
  */
723
- buttonKindByName(name: string): 'missing' | 'plain' | 'pushdown';
1161
+ buttonKindByName(name: string | number): 'missing' | 'plain' | 'pushdown';
724
1162
  /** True when the state actually changed. Mudlet answers false for a button
725
1163
  * that was already in the state asked for — "nothing to do" rather than
726
1164
  * "could not do it", which is why the caller can tell them apart only by
727
1165
  * having checked the name first. */
728
- setButtonStateByName(name: string, state: boolean): boolean;
1166
+ setButtonStateByName(name: string | number, state: boolean): boolean;
729
1167
  /** Mudlet `getButtonState(name)`. Reads the pressed state on a two-state
730
1168
  * button by name. Returns null when no such button (the Lua binding maps
731
- * that to nil — Mudlet returns false/error). */
732
- getButtonStateByName(name: string): boolean | null;
733
- /** Mudlet `setButtonStyleSheet(name, css)`. Stores raw CSS on the
734
- * ButtonNode; ButtonsBar applies it inline. */
1169
+ * that to nil — Mudlet returns false/error). A button whose code will not
1170
+ * compile still answers its state: TLuaInterpreter::getButtonState reads
1171
+ * mButtonState without asking whether the button is active. */
1172
+ getButtonStateByName(name: string | number): boolean | null;
1173
+ /** Mudlet `setButtonStyleSheet(name, css)`. Stores raw CSS on every
1174
+ * button, toolbar and menu with that name — desktop's
1175
+ * `getActionUnit()->findItems(name)` styles each match, and a toolbar's
1176
+ * sheet restyles the whole bar (mudlet-web#356). ButtonsBar applies it. */
735
1177
  setButtonStyleSheetByName(name: string, css: string): boolean;
1178
+ /**
1179
+ * Apply a change to the button bars and lay it out before the script goes
1180
+ * on. A bar along the top or bottom takes its room from the main console,
1181
+ * which getMainWindowSize() and sysWindowResizeEvent report at once on
1182
+ * desktop — and a script holds the event loop a deferred render waits for.
1183
+ */
1184
+ private layOutButtonBarsNow;
736
1185
  /**
737
1186
  * Mudlet `showToolBar(name)` / `hideToolBar(name)`. Toggles the toolbar's
738
- * own enabled flag — the ButtonsBar filters by isEffectivelyEnabled, so that
1187
+ * own enabled flag — the ButtonsBar shows only buttons whose toolbar is on, so that
739
1188
  * is the show/hide hook. Returns null on success, or the reason it moved
740
1189
  * nothing (which the Bridge shapes into Mudlet's `(nil, errMsg)`).
741
1190
  *
@@ -753,9 +1202,8 @@ export declare class ScriptingEngine implements EngineHost {
753
1202
  toggleToolBarByName(name: string, show: boolean): string | null;
754
1203
  /**
755
1204
  * Mudlet `setScript(name, luaCode[, pos])`. Replaces the source of the
756
- * `pos`-th script (1-indexed; default 1) named `name`. Updating via the
757
- * store re-runs the script load through the regular subscription pipeline,
758
- * so handlers re-register cleanly. Returns true on success, -1 if no such
1205
+ * `pos`-th script (1-indexed; default 1) named `name` and runs the new
1206
+ * body once, before this returns. Returns the script's id, -1 if no such
759
1207
  * script exists.
760
1208
  */
761
1209
  setScriptByName(name: string, code: string, pos: number): number;
@@ -794,14 +1242,42 @@ export declare class ScriptingEngine implements EngineHost {
794
1242
  /**
795
1243
  * Force-run a profile script's body right now, even if its code is unchanged.
796
1244
  * Backs the editor's "Run" / "Save & Run" button: the store subscription only
797
- * re-runs a script when its code or handlers actually change (so editing one
1245
+ * re-runs a script when its code actually changes (so editing one
798
1246
  * script doesn't re-execute its untouched siblings), which means clicking
799
1247
  * "Run" twice — or running a script you didn't edit — would otherwise do
800
- * nothing. wrapScript kills the script's previously registered anonymous
801
- * handlers before re-registering, so repeated runs stay idempotent.
1248
+ * nothing. Event-handler registrations live apart from the body (see
1249
+ * applyScriptsFromStore), so repeated runs stay idempotent.
802
1250
  */
803
1251
  runScript(scriptId: string): void;
804
1252
  private runScriptLoad;
1253
+ /**
1254
+ * Bring the runtime up to date with the scripts in the store right now,
1255
+ * and make sure the script `id` has been compiled since `before` (a
1256
+ * {@link scriptCompileSeq} read ahead of the store write): a body runs as
1257
+ * its code is set, whether or not the code changed (TScript::setScript).
1258
+ * The store subscription will usually have run it already. Returns why
1259
+ * that compile failed, or null when it ran. Backs permScript, setScript
1260
+ * and appendScript, which run the body exactly once — through here — and
1261
+ * report its error themselves.
1262
+ */
1263
+ private compileScriptNow;
1264
+ /**
1265
+ * Take in a script-tree change a Lua call just made, now rather than when
1266
+ * the store subscription next runs: it is not attached while a first
1267
+ * profile load compiles the scripts, and a script that a body switches off
1268
+ * then must stop receiving events at once, as one it replaces must not be
1269
+ * compiled again by the walk. A no-op once the subscription has seen it,
1270
+ * and before the profile's scripts were first loaded, which takes in
1271
+ * everything anyway.
1272
+ */
1273
+ private takeInScriptChanges;
1274
+ /** What a script's last compile raised, for permScript/setScript's own
1275
+ * error: the message, or for an error object that is not one, its type
1276
+ * (TLuaInterpreter treats a number as a message, as lua_isstring does). */
1277
+ private describeScriptLoadError;
1278
+ /** Why the script with this numeric id failed the last time its body ran,
1279
+ * or null if it ran cleanly. */
1280
+ scriptLoadErrorById(id: number): string | null;
805
1281
  get currentVFS(): ProfileVFS | null;
806
1282
  /**
807
1283
  * Submit one line from the command bar — Mudlet's `TCommandLine` calling
@@ -815,10 +1291,17 @@ export declare class ScriptingEngine implements EngineHost {
815
1291
  processInput(text: string): boolean;
816
1292
  /** Nesting depth of {@link processInput} — see the note there. */
817
1293
  private aliasDepth;
1294
+ /** Set when a chain hits {@link MAX_ALIAS_DEPTH}, until it unwinds to the outermost pass. */
1295
+ private aliasRunawayStopped;
1296
+ /** AliasUnit::scmMaxProcessingDepth. */
1297
+ private static readonly MAX_ALIAS_DEPTH;
818
1298
  private processInputPass;
819
1299
  /** Process a keyboard event. Returns true if a keybinding consumed it. */
820
1300
  processKey(event: KeyboardEvent): boolean;
821
1301
  raiseEvent(event: string, args?: unknown[]): void;
1302
+ /** Part of {@link EngineHost}: closeMudlet raises the exit event before it
1303
+ * disconnects. */
1304
+ raiseExitEvent(): void;
822
1305
  /** Raise sysExitEvent at most once, while the Lua runtime is still alive. */
823
1306
  private fireExit;
824
1307
  notifyMapOpen(): void;
@@ -828,9 +1311,31 @@ export declare class ScriptingEngine implements EngineHost {
828
1311
  /** Mirror a command-bar edit so Lua's getCmdLine() reads it without waiting
829
1312
  * for a re-render. Called by ProfileSession on every change. */
830
1313
  setCmdLineValue(text: string): void;
1314
+ /** What getCmdLine() answers with — the mirror, which is current the moment
1315
+ * a script writes it, unlike the React state behind it. */
1316
+ getCmdLineValue(): string;
1317
+ /** The game took hidden input (ECHO): what the command bar holds is put
1318
+ * aside as the command line, and the bar becomes the hidden-input box
1319
+ * (see ScriptingAPI.beginHiddenInput). */
1320
+ beginHiddenInput(command: string): void;
1321
+ /** The prompt for hidden input ended. */
1322
+ endHiddenInput(): void;
1323
+ /** The commands packages placed with addCommand, for the bar that draws
1324
+ * them. Narrower than handing out the whole API: the toolbar needs to read
1325
+ * the list, hear when it changes, and report a click. */
1326
+ get addonCommands(): import("../ui/commands/addonCommands").AddonCommandRegistry;
1327
+ addonCommandClicked(id: number): void;
1328
+ /** See ScriptingAPI.interceptMapperButton — the map button, menu entry and
1329
+ * shortcut ask this before toggling the map. */
1330
+ interceptMapperButton(): boolean;
1331
+ mapperButtonMode(): 'default' | 'scripted' | 'disabled';
1332
+ onMapperButtonModeChange(fn: () => void): () => void;
831
1333
  /** Hand the API a startLogging hook. Wired by ProfileSession, which owns
832
1334
  * the actual SessionLogger lifecycle. */
833
1335
  setLoggingToggler(fn: ((enabled: boolean, format: LogFormat) => boolean) | null): void;
1336
+ /** Mudlet `startLogging(state)` from outside a script — the autolog resume
1337
+ * on profile load (Host::startSavedLogging). */
1338
+ startLogging(enabled: boolean): void;
834
1339
  /** Where the live logger is writing, so startLogging can report the file. */
835
1340
  setLoggingPathProvider(fn: (() => string | null) | null): void;
836
1341
  /** Mudlet's "Show errors in main console" — when on, script errors are also
@@ -847,14 +1352,20 @@ export declare class ScriptingEngine implements EngineHost {
847
1352
  * profile VFS at `filePath` (relative paths resolve under the profile root,
848
1353
  * the same convention as `io.open`/`downloadFile`). Returns the absolute
849
1354
  * path written, or an error string (no VFS, mapper not open, or write
850
- * failure). Mudlet requires the mapper open; mudix's renderer lives in the
1355
+ * failure). Mudlet requires the mapper open; Mudlet Web's renderer lives in the
851
1356
  * map widget, so the same precondition applies.
852
1357
  */
853
- exportAreaImageToVfs(areaId: number, filePath: string, zLevel?: number): {
1358
+ exportAreaImageToVfs(areaId: number, filePath: string, zLevel?: number | true): {
854
1359
  path: string;
855
1360
  } | {
856
1361
  error: string;
1362
+ target?: boolean;
857
1363
  };
1364
+ /** exportAreaImage(areaID, filePath, true) — T2DMap::exportAreaToImage's
1365
+ * every-z-level branch: one image per level of the area, each named
1366
+ * `<base>_level_<z>.<suffix>` beside `filePath` (QFileInfo's
1367
+ * completeBaseName and suffix, `png` when there is none). */
1368
+ private exportEveryAreaLevelToVfs;
858
1369
  /**
859
1370
  * Mudlet `resetProfile()` — reload the entire profile as if just reopened:
860
1371
  * clear every UI surface, tear down and recreate the Lua runtime (fresh
@@ -865,8 +1376,12 @@ export declare class ScriptingEngine implements EngineHost {
865
1376
  * exactly why Mudlet warns against calling it from a script-item — defer it
866
1377
  * (`tempTimer(0, resetProfile)` works) or run it from the command line. A
867
1378
  * concurrent reset is coalesced.
1379
+ *
1380
+ * Answers what Host::resetProfile_phase1 does: true once the reset is
1381
+ * armed, false for one already in progress (which it folds into) or one
1382
+ * refused because the profile is closing.
868
1383
  */
869
- resetProfile(): void;
1384
+ resetProfile(): boolean;
870
1385
  private performReset;
871
1386
  /**
872
1387
  * Resolves once the initial load pass has finished (scripts/aliases/timers/
@@ -888,7 +1403,7 @@ export declare class ScriptingEngine implements EngineHost {
888
1403
  /**
889
1404
  * Report a script-initiated call that teardown refused.
890
1405
  *
891
- * Mudlet and mudix reach the same end state by opposite routes, and it is
1406
+ * Mudlet and Mudlet Web reach the same end state by opposite routes, and it is
892
1407
  * worth being precise about which:
893
1408
  *
894
1409
  * Mudlet guards the ARRIVAL side. `TMainConsole::closeEvent` raises
@@ -900,14 +1415,14 @@ export declare class ScriptingEngine implements EngineHost {
900
1415
  * postMessage all early-return. The connection is accepted, then
901
1416
  * discarded.
902
1417
  *
903
- * mudix guards the INITIATION side, because its teardown is synchronous:
1418
+ * Mudlet Web guards the INITIATION side, because its teardown is synchronous:
904
1419
  * destroy() runs start to finish with no yield point, and MudSession
905
1420
  * disposes the client immediately after, so a socket opened here would
906
1421
  * be torn down microseconds later regardless. Refusing up front is the
907
1422
  * same outcome without the pointless socket.
908
1423
  *
909
1424
  * The observable difference is only what the script is told, and there
910
- * mudix is deliberately the more honest of the two: Mudlet returns success
1425
+ * Mudlet Web is deliberately the more honest of the two: Mudlet returns success
911
1426
  * for a connection that will never deliver a byte. Hence this log line —
912
1427
  * the divergence is intentional, but it must not be silent.
913
1428
  *
@@ -925,15 +1440,111 @@ export declare class ScriptingEngine implements EngineHost {
925
1440
  */
926
1441
  private markScriptsLoaded;
927
1442
  destroy(): void;
1443
+ /** Packages and modules whose items are being read in right now — their
1444
+ * scripts are running as part of the install. */
1445
+ private readonly installing;
1446
+ /**
1447
+ * Modules whose XML stopped part-way through (#8696). The items read in
1448
+ * before the break are in the profile and running, but they are only part
1449
+ * of the module, so writing them back out over its file — which is what a
1450
+ * sync does — would destroy the rest. Kept until a read gets all the way
1451
+ * through.
1452
+ */
1453
+ private readonly unloadedModules;
1454
+ private noteModuleLoaded;
1455
+ /** Removals asked of a package or module by its own install-time scripts,
1456
+ * waiting for that install to finish. */
1457
+ private readonly heldRemovals;
1458
+ /**
1459
+ * A package's scripts run while its install is still reading it in, and a
1460
+ * one-shot installer package asks for its own removal from one of them.
1461
+ * Carried out there and then, that took the items out from under the
1462
+ * install (Mudlet #10867 — a crash there, a half-installed package here),
1463
+ * so a removal of the package being installed is held over and carried
1464
+ * out once the install is done: the install is announced, and then the
1465
+ * removal. Removing any OTHER package still happens at once. Answers
1466
+ * whether it was held; asking twice holds it once.
1467
+ */
1468
+ private holdRemovalIfInstalling;
1469
+ /** Carry out the held removals once nothing they name is installing, on the
1470
+ * next pass of the event loop — after the install that held them has
1471
+ * answered and raised its events. On the timer engine, as the postponed
1472
+ * installs are, so a spec's pumpEvents() reaches it. */
1473
+ private carryOutHeldRemovals;
1474
+ /**
1475
+ * Each item's last compile check, per kind: what it was run on (chunk name
1476
+ * and code) and the error, or null. Kept so an item is compiled again only
1477
+ * when its code or name changes, not on every reload of its unit.
1478
+ */
1479
+ private readonly compileChecks;
1480
+ /** Compile errors already put in the error log, by kind, chunk and code —
1481
+ * not by id, so a module re-read under new ids does not report again. */
1482
+ private readonly reportedCompileErrors;
1483
+ /**
1484
+ * The error compiling a piece of an item's code gives (see itemSyntaxError),
1485
+ * or null when it compiles — or when there is no runtime to ask yet, which
1486
+ * lets the item be. A new error is handed to `report`, once.
1487
+ */
1488
+ private compileError;
1489
+ /**
1490
+ * Whether an item's code will not compile — Mudlet's `mOK_code = false`,
1491
+ * or for a trigger's Lua-function pattern `mOK_init = false`. Either way
1492
+ * `Tree::canBeActivated` refuses it: the item never matches or fires, its
1493
+ * command is not sent, and `isActive` reports it off, whatever its switch
1494
+ * says. Fixing the code brings it back as its switch has it.
1495
+ *
1496
+ * The error goes in the error log once: desktop shows it on the item in
1497
+ * the editor, where it is found when the item "does nothing".
1498
+ */
1499
+ private cannotCompile;
1500
+ /** The ids of `items` whose code will not compile (see cannotCompile), for
1501
+ * their engine to leave inactive. Checks for items no longer in the list
1502
+ * are forgotten. */
1503
+ private uncompilableIds;
1504
+ /**
1505
+ * Whether a permanent item of `kind` cannot be active because something in
1506
+ * it failed to compile: its code, or (triggers and aliases) a pattern.
1507
+ */
1508
+ private itemCannotBeActive;
1509
+ /** Scripts and triggers of the package being installed that do not work,
1510
+ * gathered while it installs; null when no install is under way. */
1511
+ private installProblems;
1512
+ /**
1513
+ * Commit a package's (or module's) items with `commit` and answer what in
1514
+ * them does not work, as Host::installPackage does: every script whose body
1515
+ * stopped with an error as it ran, in the order the package lists them,
1516
+ * then every trigger whose body will not even compile — a trigger's body
1517
+ * does not run until its pattern matches, so compiling it is the only way
1518
+ * to find out now. Plain text, joined with "; ", or null when all is well.
1519
+ *
1520
+ * The console is left alone: a script asked for this install and has the
1521
+ * answer to report however it likes, and a module sync would otherwise
1522
+ * repeat it on every save for as long as the module stays broken.
1523
+ */
1524
+ private collectInstallProblems;
1525
+ /**
1526
+ * Why a trigger's patterns do not all compile, in the plain text
1527
+ * XMLimport hands back for TTrigger::setRegexCodeList's error: one
1528
+ * sentence per pattern that failed, numbered by its place in the list, or
1529
+ * null when they all compile (a trigger with no patterns is kept for its
1530
+ * script and is not broken).
1531
+ */
1532
+ private triggerPatternErrors;
928
1533
  private reportEntityError;
929
- private wrapScript;
930
1534
  private executePermAlias;
931
1535
  private executePermTrigger;
1536
+ /** Paint a trigger's built-in highlight over what one match captured, on
1537
+ * the line being processed. Shared by the single-line fire and by each
1538
+ * condition of a multiline trigger as it matches. */
1539
+ private paintHighlight;
932
1540
  private executePermKeybinding;
933
1541
  /**
934
1542
  * Run a button's command + code. The Lua `code` runs on every click.
935
1543
  * For two-state buttons, `nextState=true` (going DOWN) sends `commandDown`,
936
- * otherwise (going UP, or single-state click) sends `command`.
1544
+ * otherwise (going UP) sends `command`. A single-state button sends
1545
+ * `command` — its desktop commandButtonDown, which the importer moves
1546
+ * there. A plain button imported before that still carries the desktop
1547
+ * down command in `commandDown`, and that is the one desktop sends.
937
1548
  */
938
1549
  executeButton(button: ButtonNode, nextState: boolean): void;
939
1550
  /**
@@ -950,6 +1561,13 @@ export declare class ScriptingEngine implements EngineHost {
950
1561
  type: string;
951
1562
  fromServer?: boolean;
952
1563
  }[]): void;
1564
+ /**
1565
+ * Lead the first server group with whatever an unterminated feedTriggers
1566
+ * left held. Mudlet feeds both into the one TBuffer, whose mMudLine the
1567
+ * fed text is still sitting in, so the server's next line completes it
1568
+ * rather than arriving above it.
1569
+ */
1570
+ private withHeldFeedText;
953
1571
  /**
954
1572
  * Free everything killed while this batch was processed.
955
1573
  *
@@ -987,6 +1605,9 @@ export declare class ScriptingEngine implements EngineHost {
987
1605
  * and flushed after all lines in the batch are rendered.
988
1606
  */
989
1607
  private processLineTriggers;
1608
+ /** How many {@link processLineTriggers} passes are running, one inside the
1609
+ * other when a trigger calls feedTriggers. */
1610
+ private lineTriggerDepth;
990
1611
  private emit;
991
1612
  private bridgeEvents;
992
1613
  }