@mudlet/mudlet-web 0.5.0 → 1.0.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 (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 +22 -14
  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
@@ -16,7 +16,7 @@
16
16
  * the callers render nothing.
17
17
  */
18
18
  import type { ComponentType } from 'react';
19
- import type { CredentialVault, VaultSnapshot } from './CredentialVault';
19
+ import type { CredentialVault, VaultSignIn, VaultSnapshot } from './CredentialVault';
20
20
  /** Props of the vault's modal. Declared here, not in the component, so this
21
21
  * module can describe the UI it hands out without importing it. */
22
22
  export interface VaultUIProps {
@@ -54,5 +54,27 @@ export declare function vaultPassword(connectionId: string): string | undefined;
54
54
  /** Whether this profile has a stored password — true even while locked, which
55
55
  * is what tells the app an unlock is worth offering. */
56
56
  export declare function vaultHasEntry(connectionId: string): boolean;
57
- /** Whether opening this profile should ask for an unlock first. */
57
+ /** Whether opening this profile should ask for an unlock first — it has a
58
+ * saved password or a saved GMCP sign-in token, and the vault is shut. */
58
59
  export declare function vaultNeedsUnlock(connectionId: string): boolean;
60
+ /** The profile's saved GMCP `Char.Login` sign-in, or `undefined` when there is
61
+ * no vault, no entry, or the vault is locked. */
62
+ export declare function vaultSignIn(connectionId: string): VaultSignIn | undefined;
63
+ /** Whether a vault could be set up here but none exists yet. False with no
64
+ * vault installed (a branded build) or no crypto (an insecure context). */
65
+ export declare function vaultMissing(): boolean;
66
+ /** Whether a vault exists and is locked. */
67
+ export declare function vaultLocked(): boolean;
68
+ /** Whether this profile has a saved sign-in token — true even while locked. */
69
+ export declare function vaultHasSignIn(connectionId: string): boolean;
70
+ /**
71
+ * Whether a sign-in token handed to us right now would be kept — the honest
72
+ * answer to GMCP's `token_storage`. With no vault (a branded build, or a player
73
+ * who never set one up) or a locked one, a token would be thrown away, and the
74
+ * standard asks the client to say so up front, so the game does not offer the
75
+ * player a "remember me" that cannot happen.
76
+ */
77
+ export declare function vaultCanStoreSignIn(): boolean;
78
+ /** Save (or with `null` forget) a profile's sign-in. Resolves `false` when it
79
+ * could not — no vault, locked, or the write failed. */
80
+ export declare function saveVaultSignIn(connectionId: string, entry: VaultSignIn | null): Promise<boolean>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The manual page for the credential vault.
3
+ *
4
+ * It lives here rather than in `ui/helpTopics.ts` for the same reason the vault
5
+ * itself does: a branded build ships for one game, has no vault, and must not
6
+ * carry a help topic explaining a feature its players cannot find. Registered
7
+ * from `main.tsx` at boot — the standalone app's entry, never the library's.
8
+ */
9
+ export declare function installVaultHelpTopic(): void;
@@ -14,7 +14,7 @@
14
14
  * with a profile export.
15
15
  */
16
16
  import type { Ciphertext } from './vaultCrypto';
17
- export declare const VAULT_STORAGE_KEY = "mudix_vault_v1";
17
+ export declare const VAULT_STORAGE_KEY = "mudlet_vault_v1";
18
18
  interface UnlockerBase {
19
19
  /** Stable local id, so the manage UI can remove one unambiguously. */
20
20
  id: string;
@@ -51,6 +51,38 @@ export interface VaultRecord {
51
51
  /** AES-GCM under the master key over `Record<connectionId, password>`.
52
52
  * `null` before the first secret is stored. */
53
53
  payload: Ciphertext | null;
54
+ /** Profiles holding a saved GMCP `Char.Login` sign-in token (see
55
+ * {@link VaultSignIn}). Plaintext for the same reason as `entryIds`: a
56
+ * locked vault has to be able to say a profile has something worth
57
+ * unlocking for. Absent in a record written before sign-ins existed. */
58
+ signInIds?: string[];
59
+ /** AES-GCM under the master key over `Record<connectionId, VaultSignIn>`.
60
+ * A field of its own rather than more keys in `payload`, so a build from
61
+ * before sign-ins existed still reads its passwords unchanged, and carries
62
+ * this across its own writes untouched (it spreads the record). */
63
+ signInPayload?: Ciphertext | null;
64
+ }
65
+ /**
66
+ * A saved GMCP `Char.Login` v2 sign-in: the reconnect token a game issued with
67
+ * `Char.Login.Token`, the account it names, and what is needed to replay it
68
+ * safely — or to resume the same provider once it stops working.
69
+ *
70
+ * Mudlet keeps the same entry in the OS keychain (`GMCPAuthenticator`'s
71
+ * metadata + token keys). The token is a bearer secret — it signs the account
72
+ * in without a password — so it lives encrypted here or not at all.
73
+ */
74
+ export interface VaultSignIn {
75
+ /** The account the token was issued for; `Char.Login.Reconnect` names it. */
76
+ account: string;
77
+ /** Provider id (`discord`, `google`, …) learned from `Char.Login.URL`, so a
78
+ * dead token can turn into a resume of that provider's sign-in. */
79
+ provider?: string;
80
+ /** The bearer token. Absent in a resume hint left behind by a dead one. */
81
+ token?: string;
82
+ /** The token may only be replayed over an encrypted game connection — the
83
+ * issuing server's requirement, stored because the connection that set it
84
+ * is long gone by replay time. Missing reads as true, never widening. */
85
+ secureOnly?: boolean;
54
86
  }
55
87
  /** Parse defensively — a corrupt record must degrade to "no vault", never to a
56
88
  * crash on boot that locks the user out of the app as well as the vault. */
@@ -1,26 +1,233 @@
1
- // Service worker that serves ProfileVFS-backed assets at /__vfs/<connectionId>/<path>.
2
- // The page is the source of truth for VFS contents (the SW can't share folder
3
- // handles or always-open the same IDB store), so each request round-trips to
4
- // the client via MessageChannel.
1
+ // The Mudlet Web service worker. Two jobs that share nothing but this file:
2
+ //
3
+ // 1. ProfileVFS-backed assets at /__vfs/<connectionId>/<path>. The page is the
4
+ // source of truth for VFS contents (the SW can't share folder handles or
5
+ // always-open the same IDB store), so each request round-trips to the client
6
+ // via MessageChannel.
7
+ //
8
+ // 2. The app shell — the built HTML, JS, CSS and WASM — cached so an installed
9
+ // Mudlet Web opens offline instead of the browser's error page. There is no
10
+ // game to play without a network, but profiles, scripts, triggers, maps and
11
+ // logs all live in browser storage, and reaching them shouldn't need one.
12
+ // The manifest has advertised `display: standalone` since day one; this is
13
+ // what backs the promise (issue #71).
5
14
 
6
- const CACHE_NAME = 'mudix-vfs-v1';
15
+ const CACHE_NAME = 'mudlet-vfs-v1';
16
+ const APP_CACHE = 'mudlet-app-v1';
7
17
  // Scope path always ends with '/'. On a root-served deploy this is '/'; on
8
18
  // GitHub Pages or any subpath deploy it's '/<repo>/'. The intercept prefix is
9
19
  // '<scope>__vfs/' so SW-controlled URLs stay inside scope.
10
20
  const SCOPE_PATH = new URL(self.registration.scope).pathname;
11
21
  const PREFIX = `${SCOPE_PATH}__vfs/`;
22
+ // The one entry every navigation resolves to. Deep links (?profile=<id>) must
23
+ // not each earn a cache entry of their own, and any of them is served by this
24
+ // same document.
25
+ const SHELL_URL = SCOPE_PATH;
26
+ // Where the build id of the cached generation is kept — inside the cache it
27
+ // describes, so it survives the SW being killed and restarted without a second
28
+ // storage API. `__`-prefixed like `__vfs/`, which no real asset path uses.
29
+ const BUILD_KEY = `${SCOPE_PATH}__app-build`;
12
30
  const READ_TIMEOUT_MS = 5000;
31
+ // Whether this registration is allowed to cache the app at all. Set from the
32
+ // script URL by the page (`vfs-sw.js?app-shell=1`), which only a built app asks
33
+ // for — a dev server has no content-hashed assets to cache, and caching the
34
+ // files it does serve under fixed names is cost with no offline to show for it.
35
+ // It has to be known here, at evaluation time, because the first fetch event can
36
+ // arrive long before any message from the page.
37
+ const APP_SHELL = new URL(self.location.href).searchParams.get('app-shell') === '1';
13
38
 
14
- self.addEventListener('install', () => self.skipWaiting());
15
- self.addEventListener('activate', (e) => e.waitUntil(self.clients.claim()));
39
+ // What may be cached as part of the app. Deliberately narrow rather than
40
+ // "anything same-origin": it admits Vite's content-hashed output and the static
41
+ // files index.html names, and nothing else. That is also what keeps `yarn dev`
42
+ // honest — a dev server serves modules from /src/, /@vite/ and /node_modules/,
43
+ // none of which match, so hot reload never races a cached copy.
44
+ const HASHED_ASSET = /\/assets\/[^/]+-[A-Za-z0-9_-]{8,}\.[^/]+$/;
45
+ // The handful of app files that keep a fixed name: the icons and manifest
46
+ // index.html points at, and the WASM the plugin emits at the scope root
47
+ // (libpcre2.wasm) rather than into assets/.
48
+ const STATIC_FILE = /\/(?:manifest\.webmanifest|icon[a-z0-9-]*\.(?:svg|png)|favicon\.ico|[^/]+\.wasm)$/;
49
+
50
+ // Every app-cache lookup ignores Vary, and it is not an optimisation — without
51
+ // it the app does not load offline at all. Static hosts answer these files with
52
+ // `Vary: Origin` (vite preview and GitHub Pages both do), and Vite's built HTML
53
+ // asks for its bundle with `crossorigin`, so the parser's request carries an
54
+ // `Origin` header that the copy stored by `cache.add()` does not. Cache matching
55
+ // then declares them different requests, the cache misses, and the fetch behind
56
+ // it fails with the network gone — a blank page, from a cache holding exactly
57
+ // the right bytes under exactly the right URL. None of these responses actually
58
+ // differ by origin: they are static files on one origin.
59
+ const MATCH = { ignoreVary: true };
60
+
61
+ function inScope(url) {
62
+ return url.origin === self.location.origin
63
+ && url.pathname.startsWith(SCOPE_PATH)
64
+ && !url.pathname.startsWith(PREFIX);
65
+ }
66
+
67
+ function isAppAsset(url) {
68
+ return inScope(url) && (HASHED_ASSET.test(url.pathname) || STATIC_FILE.test(url.pathname));
69
+ }
70
+
71
+ self.addEventListener('install', (event) => {
72
+ self.skipWaiting();
73
+ if (APP_SHELL) event.waitUntil(cacheShell());
74
+ });
75
+
76
+ self.addEventListener('activate', (event) => event.waitUntil((async () => {
77
+ // Anything left by an older worker of ours under a name this one no longer
78
+ // uses. Both prefixes: these caches were named `mudlet-*` before the storage
79
+ // rename, and an old worker's leftovers should be reclaimed rather than left
80
+ // to sit against the origin's quota forever. Scoped to our own prefixes
81
+ // rather than "every cache on the
82
+ // origin": a branded build embeds this worker in somebody else's site, and
83
+ // their caches are none of our business.
84
+ const names = await caches.keys();
85
+ await Promise.all(names
86
+ .filter((n) => (n.startsWith('mudlet-') || n.startsWith('mudix-'))
87
+ && n !== CACHE_NAME && n !== APP_CACHE)
88
+ .map((n) => caches.delete(n)));
89
+ await self.clients.claim();
90
+ })()));
16
91
 
17
92
  self.addEventListener('fetch', (event) => {
18
- const url = new URL(event.request.url);
93
+ const request = event.request;
94
+ if (request.method !== 'GET') return;
95
+ const url = new URL(request.url);
19
96
  if (url.origin !== self.location.origin) return;
20
- if (!url.pathname.startsWith(PREFIX)) return;
21
- event.respondWith(handle(event, url));
97
+ if (url.pathname.startsWith(PREFIX)) {
98
+ event.respondWith(handle(event, url));
99
+ return;
100
+ }
101
+ if (!APP_SHELL) return;
102
+ // Navigations revalidate against the server, so a deploy is picked up on the
103
+ // next load rather than whenever the cache happens to turn over; the cached
104
+ // shell is strictly the offline answer. See shellFirst for why "network
105
+ // first" is not enough on its own here.
106
+ if (request.mode === 'navigate' && url.pathname.startsWith(SCOPE_PATH)) {
107
+ event.respondWith(shellFirst(request));
108
+ return;
109
+ }
110
+ if (!inScope(url)) return;
111
+ // Hashed filenames are immutable by construction: a changed file is a
112
+ // changed URL, so a hit is never stale and revalidating one would be a
113
+ // round-trip spent to be told nothing.
114
+ if (HASHED_ASSET.test(url.pathname)) event.respondWith(cacheFirst(request));
115
+ // The fixed-name files can change under the same URL, so they are answered
116
+ // from the cache and refreshed behind it — offline-proof without ever
117
+ // pinning a stale icon or an old libpcre2.wasm to a dev server.
118
+ else if (STATIC_FILE.test(url.pathname)) event.respondWith(staleWhileRevalidate(request));
22
119
  });
23
120
 
121
+ async function cacheShell() {
122
+ try {
123
+ const cache = await caches.open(APP_CACHE);
124
+ // `reload` so an install triggered by a reload of a stale page doesn't
125
+ // seed the cache from the HTTP cache's copy of the old document.
126
+ await cache.put(SHELL_URL, await fetch(new Request(SHELL_URL, { cache: 'reload' })));
127
+ } catch {
128
+ // Installed while offline, or the shell 404s under this scope. The first
129
+ // successful navigation fills it in.
130
+ }
131
+ }
132
+
133
+ async function shellFirst(request) {
134
+ const cache = await caches.open(APP_CACHE);
135
+ try {
136
+ // Revalidate rather than `fetch(request)`. A navigation request carries
137
+ // cache mode `default`, so the plain form is answered from the browser
138
+ // HTTP cache — and GitHub Pages stamps every file it serves, index.html
139
+ // included, with `max-age=600`. That turned this "network first" branch
140
+ // into "ten-minute-old document first": the shell it returned could name
141
+ // content-hashed assets that the deploy had already deleted, so the entry
142
+ // module 404'd and the page came up blank. `no-cache` means revalidate,
143
+ // not refetch — the usual answer is a 304 on a 4KB document — and a
144
+ // server that cannot be reached still throws, so the offline path below
145
+ // is unchanged.
146
+ const response = await fetch(new Request(request, { cache: 'no-cache' }));
147
+ if (response.ok && response.type === 'basic') {
148
+ cache.put(SHELL_URL, response.clone()).catch(() => {});
149
+ }
150
+ return response;
151
+ } catch {
152
+ return (await cache.match(SHELL_URL, MATCH)) ?? Response.error();
153
+ }
154
+ }
155
+
156
+ async function cacheFirst(request) {
157
+ const cache = await caches.open(APP_CACHE);
158
+ const hit = await cache.match(request, MATCH);
159
+ if (hit) return hit;
160
+ try {
161
+ const response = await fetch(request);
162
+ if (response.ok && response.type === 'basic') {
163
+ cache.put(request, response.clone()).catch(() => {});
164
+ }
165
+ return response;
166
+ } catch {
167
+ return Response.error();
168
+ }
169
+ }
170
+
171
+ async function staleWhileRevalidate(request) {
172
+ const cache = await caches.open(APP_CACHE);
173
+ const hit = await cache.match(request, MATCH);
174
+ const network = fetch(request).then((response) => {
175
+ if (response.ok && response.type === 'basic') {
176
+ cache.put(request, response.clone()).catch(() => {});
177
+ }
178
+ return response;
179
+ });
180
+ if (hit) {
181
+ // Let the refresh finish after the response has gone out.
182
+ network.catch(() => {});
183
+ return hit;
184
+ }
185
+ try {
186
+ return await network;
187
+ } catch {
188
+ return Response.error();
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Cache everything the page has already loaded, on the page's say-so.
194
+ *
195
+ * A first visit is not controlled by the worker until it claims, by which time
196
+ * the bundle has been fetched uncached — so without this, offline would only
197
+ * work from the *second* visit. The page sends the resource list it actually
198
+ * loaded (chunks and WASM included), which is more than this file could guess.
199
+ * Chunks loaded lazily later in an uncontrolled first session are the one gap,
200
+ * and they are picked up by `cacheFirst` on the next visit.
201
+ */
202
+ async function precacheApp({ build, urls }) {
203
+ let cache = await caches.open(APP_CACHE);
204
+ const wanted = (Array.isArray(urls) ? urls : []).filter((raw) => {
205
+ try { return isAppAsset(new URL(raw, self.location.href)); } catch { return false; }
206
+ });
207
+ // A deploy renames every hashed asset, so the previous generation's entries
208
+ // are unreachable dead weight — drop the lot rather than grow forever.
209
+ // Keyed off the *app's* build id, not a constant in this file: this file
210
+ // changes about once a year, so a version bumped here would never fire.
211
+ //
212
+ // Only ever on a list with something in it. An empty one means the page
213
+ // could not enumerate what it loaded, and emptying a working cache on the
214
+ // strength of that would leave the app less able to open offline than
215
+ // before, which is the opposite of the point.
216
+ const stamped = await cache.match(BUILD_KEY, MATCH);
217
+ if (wanted.length > 0 && (stamped ? await stamped.text() : null) !== build) {
218
+ await caches.delete(APP_CACHE);
219
+ cache = await caches.open(APP_CACHE);
220
+ await cache.put(BUILD_KEY, new Response(build));
221
+ await cacheShell();
222
+ }
223
+ await Promise.all(wanted.map(async (url) => {
224
+ if (await cache.match(url, MATCH)) return;
225
+ // One asset that has since 404'd must not take the rest with it, which
226
+ // is what cache.addAll() would do.
227
+ try { await cache.add(url); } catch { /* keep going */ }
228
+ }));
229
+ }
230
+
24
231
  async function handle(event, url) {
25
232
  const rest = url.pathname.slice(PREFIX.length).split('/').filter(Boolean);
26
233
  if (rest.length < 2) return new Response('Bad request', { status: 400 });
@@ -35,7 +242,7 @@ async function handle(event, url) {
35
242
  if (!client) {
36
243
  // Either there's no app tab loaded (direct URL hit in fresh tab) or
37
244
  // the only candidate is the tab currently navigating to this URL.
38
- return new Response('No app tab loaded; open mudix first', { status: 503 });
245
+ return new Response('No app tab loaded; open Mudlet Web first', { status: 503 });
39
246
  }
40
247
 
41
248
  const reply = await ask(client, { type: 'vfs:read', connectionId, path: filePath });
@@ -102,6 +309,8 @@ self.addEventListener('message', (event) => {
102
309
  if (!data) return;
103
310
  if (data.type === 'vfs:invalidate') {
104
311
  event.waitUntil(invalidate(data));
312
+ } else if (data.type === 'app:precache' && APP_SHELL) {
313
+ event.waitUntil(precacheApp(data));
105
314
  }
106
315
  });
107
316
 
@@ -1,2 +1,2 @@
1
1
  import type { PluginOption } from 'vite';
2
- export default function mudix(): PluginOption[];
2
+ export default function mudlet(): PluginOption[];
package/dist-lib/vite.js CHANGED
@@ -3,6 +3,7 @@ import { createRequire } from 'node:module';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { nodePolyfills } from 'vite-plugin-node-polyfills';
6
+ import { patchLibpcre2Wasm } from './pcre2Wasm.js';
6
7
  /**
7
8
  * The `@mudlet/mudlet-web/vite` companion plugin. The library leaves all of its
8
9
  * heavyweight dependencies external, so the consumer's Vite processes them —
@@ -19,10 +20,11 @@ import { nodePolyfills } from 'vite-plugin-node-polyfills';
19
20
  */
20
21
  const require = createRequire(import.meta.url);
21
22
  const POLYFILLS = ['buffer', 'stream', 'events', 'util'];
22
- /** vfs-sw.js ships next to the compiled plugin in dist-lib (consumers) and in
23
- * public/ when running from the mudix repo itself (source import). */
24
- function resolveVfsSwPath() {
25
- for (const rel of ['./vfs-sw.js', '../public/vfs-sw.js']) {
23
+ /** The static files the app needs at its root (vfs-sw.js, oauth-callback.html)
24
+ * ship next to the compiled plugin in dist-lib (consumers) and in public/ when
25
+ * running from the Mudlet Web repo itself (source import). */
26
+ function resolveStaticPath(name) {
27
+ for (const rel of [`./${name}`, `../public/${name}`]) {
26
28
  const p = fileURLToPath(new URL(rel, import.meta.url));
27
29
  if (existsSync(p))
28
30
  return p;
@@ -31,18 +33,28 @@ function resolveVfsSwPath() {
31
33
  }
32
34
  /** Serves libpcre2.wasm at the root URL in dev (where emscripten looks for it
33
35
  * when document.currentScript is null) and emits it to the build output.
34
- * Resolved from wherever pcre2-wasm-universal lives relative to mudix. */
36
+ * Resolved from wherever pcre2-wasm-universal lives relative to mudlet, and
37
+ * patched on the way out so `_match` takes an options argument — without it a
38
+ * trigger's match-all is quadratic in the line's length (see pcre2Wasm.ts).
39
+ * A binary the patch doesn't recognise goes out as shipped: slower, not wrong.
40
+ * That fallback is silent here on purpose (a consumer's build shouldn't break
41
+ * over speed); tests/triggers/pcreMatchAllLinear.test.ts is what turns a
42
+ * pcre2-wasm-universal bump the patch no longer fits into a red CI run. */
35
43
  function pcre2WasmPlugin() {
36
44
  // The wasm file isn't in the package's exports map — resolve the exported
37
45
  // ./libpcre2 entry (dist/libpcre2.js) and take its sibling.
38
46
  const wasmPath = join(dirname(require.resolve('pcre2-wasm-universal/libpcre2')), 'libpcre2.wasm');
47
+ const wasm = () => {
48
+ const shipped = readFileSync(wasmPath);
49
+ return patchLibpcre2Wasm(shipped) ?? shipped;
50
+ };
39
51
  return {
40
- name: 'mudix:pcre2-wasm',
52
+ name: 'mudlet:pcre2-wasm',
41
53
  configureServer(server) {
42
54
  server.middlewares.use((req, res, next) => {
43
55
  if (req.url === '/libpcre2.wasm') {
44
56
  res.setHeader('Content-Type', 'application/wasm');
45
- res.end(readFileSync(wasmPath));
57
+ res.end(wasm());
46
58
  return;
47
59
  }
48
60
  next();
@@ -52,80 +64,90 @@ function pcre2WasmPlugin() {
52
64
  this.emitFile({
53
65
  type: 'asset',
54
66
  fileName: 'libpcre2.wasm',
55
- source: readFileSync(wasmPath),
67
+ source: wasm(),
56
68
  });
57
69
  },
58
70
  };
59
71
  }
60
- /** Serves/emits the VFS service worker at the site root so
61
- * `registerVfsServiceWorker()` (called by MudletWebApp) finds it. Skipped when
62
- * the consumer already ships its own copy in public/ — as the standalone
63
- * mudix app does. */
64
- function vfsServiceWorkerPlugin() {
65
- const swPath = resolveVfsSwPath();
72
+ /** Serves/emits a static file at the site root. Used for the VFS service
73
+ * worker, so `registerVfsServiceWorker()` (called by MudletWebApp) finds it,
74
+ * and for `oauth-callback.html`, the redirect target of the client-driven GMCP
75
+ * `Char.Login` browser sign-in (see oauthClientFlow.ts). Skipped when the
76
+ * consumer already ships its own copy in public/ — as the standalone Mudlet
77
+ * Web app does. */
78
+ function rootStaticFilePlugin(name, contentType) {
79
+ const filePath = resolveStaticPath(name);
66
80
  let skip = false;
67
81
  return {
68
- name: 'mudix:vfs-sw',
82
+ name: `mudlet:static:${name}`,
69
83
  configResolved(config) {
70
- skip = !swPath || (!!config.publicDir && existsSync(join(config.publicDir, 'vfs-sw.js')));
84
+ skip = !filePath || (!!config.publicDir && existsSync(join(config.publicDir, name)));
71
85
  },
72
86
  configureServer(server) {
73
87
  server.middlewares.use((req, res, next) => {
74
- if (!skip && swPath && req.url?.split('?')[0] === '/vfs-sw.js') {
75
- res.setHeader('Content-Type', 'text/javascript');
76
- res.end(readFileSync(swPath));
88
+ if (!skip && filePath && req.url?.split('?')[0] === `/${name}`) {
89
+ res.setHeader('Content-Type', contentType);
90
+ res.end(readFileSync(filePath));
77
91
  return;
78
92
  }
79
93
  next();
80
94
  });
81
95
  },
82
96
  generateBundle() {
83
- if (skip || !swPath)
97
+ if (skip || !filePath)
84
98
  return;
85
99
  this.emitFile({
86
100
  type: 'asset',
87
- fileName: 'vfs-sw.js',
88
- source: readFileSync(swPath, 'utf8'),
101
+ fileName: name,
102
+ source: readFileSync(filePath, 'utf8'),
89
103
  });
90
104
  },
91
105
  };
92
106
  }
93
- export default function mudix() {
107
+ export default function mudlet() {
94
108
  return [
95
109
  {
96
- name: 'mudix:config',
110
+ name: 'mudlet:config',
97
111
  config: () => ({
98
112
  resolve: {
99
- // Exactly one React instance, always. `mudlet-map-editor`
100
- // declares react/react-dom as plain *dependencies* (not
101
- // peers), so the moment its range outruns the range the
102
- // app resolved, the package manager nests a second copy
103
- // under the editor. The editor's `App` is then rendered by
104
- // mudix's React while its hooks come from the nested one,
105
- // whose dispatcher is null — "Invalid hook call", and with
106
- // no error boundary above the lazy boundary the throw
113
+ // Exactly one instance of each, always. `mudlet-map-editor`
114
+ // used to declare these as plain *dependencies*, so the
115
+ // moment its range outran the range the app resolved, the
116
+ // package manager nested a second copy under the editor.
117
+ // The editor's `App` was then rendered by Mudlet Web's React
118
+ // while its hooks came from the nested one, whose
119
+ // dispatcher is null — "Invalid hook call", and with no
120
+ // error boundary above the lazy boundary the throw
107
121
  // unmounts the whole root, so opening the map editor
108
122
  // blanked the entire UI in dev and in production alike.
109
- // Deduping is the structural fix: it survives the next
110
- // version skew, and consumers of the library (which
111
- // externalizes react) get it through this plugin too.
112
- dedupe: ['react', 'react-dom'],
123
+ // Editor 2.0.0 makes all of them peer dependencies, which
124
+ // is the fix at the source; this stays as the backstop that
125
+ // does not depend on the package manager hoisting correctly
126
+ // — and consumers of the library (which externalizes react)
127
+ // get it through this plugin too. Konva and the renderer
128
+ // are here for the same reason and not only for symmetry:
129
+ // two Konvas split the stage registry, and two renderers
130
+ // disagree on scene structure, both silently.
131
+ dedupe: ['react', 'react-dom', 'konva', 'mudlet-map-renderer'],
113
132
  },
114
133
  // A Mudlet package archive is a zip, not source. `?url` imports
115
134
  // get away without this (the explicit query short-circuits
116
135
  // import analysis), but `?inline` — which the busted fixtures
117
136
  // use to carry an archive into the VFS — reaches the asset
118
137
  // pipeline and needs the extension declared.
119
- assetsInclude: ['**/*.mpackage'],
138
+ // The map fixtures are plain `.zip` and binary `.dat`, and scoping
139
+ // those to the fixture tree keeps a bare import of either anywhere
140
+ // else meaning what it means today.
141
+ assetsInclude: ['**/*.mpackage', '**/specs/fixtures/**/*.zip', '**/specs/fixtures/**/*.dat'],
120
142
  optimizeDeps: {
121
- // 'mudix': the library entry carries relative `?url` asset
143
+ // 'Mudlet Web': the library entry carries relative `?url` asset
122
144
  // imports (external in the lib build); the dep optimizer's
123
145
  // scanner treats the query as part of a filesystem path and
124
- // dies on Windows (os error 123). Excluded, mudix is served
146
+ // dies on Windows (os error 123). Excluded, Mudlet Web is served
125
147
  // through Vite's transform pipeline in dev, where `?url`
126
- // works. Harmless in mudix's own repo (not a dep there).
148
+ // works. Harmless in Mudlet Web's own repo (not a dep there).
127
149
  exclude: ['pcre2-wasm-universal', '@mudlet/mudlet-web'],
128
- // CJS deps reached from the excluded mudix entry must be
150
+ // CJS deps reached from the excluded Mudlet Web entry must be
129
151
  // pre-bundled explicitly (Vite doesn't interop CJS served
130
152
  // raw). Extend this list if dev mode reports "does not
131
153
  // provide an export named ..." for another dependency.
@@ -136,7 +158,7 @@ export default function mudix() {
136
158
  // html-parse-stringify > void-elements) are CJS, and which
137
159
  // of them trips first depends on evaluation order. Listing
138
160
  // the editor pre-bundles the lot in one go — and mirrors
139
- // mudix's own dev server, where the scanner finds the
161
+ // Mudlet Web's own dev server, where the scanner finds the
140
162
  // `import('mudlet-map-editor')` in MapEditorModal and
141
163
  // pre-bundles it anyway. Bare package names only, no
142
164
  // subpaths: `mudlet-map-renderer/bigmap` and friends only
@@ -171,6 +193,7 @@ export default function mudix() {
171
193
  },
172
194
  nodePolyfills({ include: POLYFILLS }),
173
195
  pcre2WasmPlugin(),
174
- vfsServiceWorkerPlugin(),
196
+ rootStaticFilePlugin('vfs-sw.js', 'text/javascript'),
197
+ rootStaticFilePlugin('oauth-callback.html', 'text/html; charset=utf-8'),
175
198
  ];
176
199
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mudlet/mudlet-web",
3
- "version": "0.5.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "description": "Mudlet Web — Mudlet in the browser, usable standalone or as a library for branded builds",
6
6
  "license": "GPL-2.0-or-later",
@@ -49,7 +49,9 @@
49
49
  "busted:failures": "playwright test -c playwright.failures.config.ts",
50
50
  "sync:mudlet-specs": "node scripts/sync-mudlet-specs.mjs",
51
51
  "sync:mudlet-lua": "node scripts/sync-mudlet-lua.mjs",
52
- "sync:mudlet-games": "node scripts/sync-mudlet-games.mjs"
52
+ "sync:mudlet-games": "node scripts/sync-mudlet-games.mjs",
53
+ "check:vendored": "node scripts/check-vendored-paths.mjs",
54
+ "test:e2e:upgrade": "playwright test -c playwright.upgrade.config.ts"
53
55
  },
54
56
  "dependencies": {
55
57
  "@codemirror/autocomplete": "^6.20.1",
@@ -57,25 +59,29 @@
57
59
  "@codemirror/lang-json": "^6.0.2",
58
60
  "@codemirror/language": "^6.12.3",
59
61
  "@codemirror/legacy-modes": "^6.5.2",
60
- "@codemirror/state": "^6.6.0",
62
+ "@codemirror/search": "^6.7.2",
63
+ "@codemirror/state": "^6.7.4",
61
64
  "@codemirror/theme-one-dark": "^6.1.3",
62
- "@codemirror/view": "^6.41.1",
65
+ "@codemirror/view": "^6.43.11",
63
66
  "@lezer/highlight": "^1.2.3",
64
67
  "@sqlite.org/sqlite-wasm": "^3.53.0-build1",
65
68
  "@zenfs/core": "^2.5.6",
66
69
  "@zenfs/dom": "^1.2.9",
67
70
  "dompurify": "^3.4.14",
68
71
  "fflate": "^0.8.2",
72
+ "i18next": "^26.3.6",
73
+ "konva": "^10.3.0",
69
74
  "lucide-react": "^1.14.0",
70
75
  "marked": "^18.0.4",
71
- "mudlet-map-binary-reader": "^1.2.0",
72
- "mudlet-map-editor": "^1.3.2",
73
- "mudlet-map-renderer": "^2.6.1",
76
+ "mudlet-map-binary-reader": "^1.3.0",
77
+ "mudlet-map-editor": "^2.0.0",
78
+ "mudlet-map-renderer": "^3.0.0",
74
79
  "pako": "^2.1.0",
75
80
  "pcre2-wasm-universal": "^1.0.0",
76
- "react": "^19.2.0",
77
- "react-dom": "^19.2.0",
78
- "vite-plugin-node-polyfills": "^0.26.0",
81
+ "react": "^19.2.8",
82
+ "react-dom": "^19.2.8",
83
+ "react-i18next": "^17.0.11",
84
+ "vite-plugin-node-polyfills": "^0.28.0",
79
85
  "wasmoon-lua5.1": "^1.18.10",
80
86
  "zustand": "^5.0.12"
81
87
  },
@@ -86,12 +92,14 @@
86
92
  "@types/react": "^19.2.0",
87
93
  "@types/react-dom": "^19.2.0",
88
94
  "@vitejs/plugin-react": "^6.0.1",
89
- "happy-dom": "^20.9.0",
95
+ "happy-dom": "^21.0.4",
90
96
  "typescript": "^5.0.0",
91
- "vite": "8.0.16",
92
- "vitest": "^4.1.7"
97
+ "vite": "8.1.6",
98
+ "vitest": "^4.1.12"
93
99
  },
94
100
  "resolutions": {
95
- "dompurify": "^3.4.14"
101
+ "dompurify": "^3.4.14",
102
+ "@codemirror/state": "^6.7.4",
103
+ "@codemirror/view": "^6.43.11"
96
104
  }
97
105
  }