waybetter 0.1.1 → 0.6.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 (515) hide show
  1. package/README.md +140 -6
  2. package/bin/waybetter.mjs +46 -0
  3. package/build/runtime.mjs +105 -0
  4. package/cli/buildenv.mjs +130 -0
  5. package/cli/dev.mjs +97 -0
  6. package/cli/i18n.mjs +382 -0
  7. package/cli/manifests.mjs +383 -0
  8. package/cli/privacy.mjs +768 -0
  9. package/cli/release.mjs +444 -0
  10. package/cli/remote.mjs +260 -0
  11. package/cli/store.mjs +326 -0
  12. package/cli/strings.mjs +121 -0
  13. package/dist/runtime/column.d.ts +93 -0
  14. package/dist/runtime/column.js +451 -0
  15. package/dist/runtime/column.js.map +1 -0
  16. package/dist/runtime/commandReport.d.ts +19 -0
  17. package/dist/runtime/commandReport.js +47 -0
  18. package/dist/runtime/commandReport.js.map +1 -0
  19. package/dist/runtime/commands.d.ts +72 -0
  20. package/dist/runtime/commands.js +214 -0
  21. package/dist/runtime/commands.js.map +1 -0
  22. package/dist/runtime/devErrors.d.ts +16 -0
  23. package/dist/runtime/devErrors.js +30 -0
  24. package/dist/runtime/devErrors.js.map +1 -0
  25. package/dist/runtime/domHub.d.ts +21 -0
  26. package/dist/runtime/domHub.js +139 -4
  27. package/dist/runtime/domHub.js.map +1 -1
  28. package/dist/runtime/featureModules.d.ts +157 -0
  29. package/dist/runtime/featureModules.js +484 -0
  30. package/dist/runtime/featureModules.js.map +1 -0
  31. package/dist/runtime/featureTable.d.ts +144 -0
  32. package/dist/runtime/featureTable.js +223 -0
  33. package/dist/runtime/featureTable.js.map +1 -0
  34. package/dist/runtime/fonts.d.ts +22 -0
  35. package/dist/runtime/fonts.js +72 -0
  36. package/dist/runtime/fonts.js.map +1 -0
  37. package/dist/runtime/i18n.d.ts +138 -0
  38. package/dist/runtime/i18n.js +614 -0
  39. package/dist/runtime/i18n.js.map +1 -0
  40. package/dist/runtime/i18nCheck.d.ts +30 -0
  41. package/dist/runtime/i18nCheck.js +224 -0
  42. package/dist/runtime/i18nCheck.js.map +1 -0
  43. package/dist/runtime/pageLang.d.ts +8 -0
  44. package/dist/runtime/pageLang.js +64 -0
  45. package/dist/runtime/pageLang.js.map +1 -0
  46. package/dist/runtime/pageStrings.d.ts +35 -0
  47. package/dist/runtime/pageStrings.js +76 -0
  48. package/dist/runtime/pageStrings.js.map +1 -0
  49. package/dist/runtime/panelButton.d.ts +33 -0
  50. package/dist/runtime/panelButton.js +83 -0
  51. package/dist/runtime/panelButton.js.map +1 -0
  52. package/dist/runtime/permissions.d.ts +47 -0
  53. package/dist/runtime/permissions.js +141 -0
  54. package/dist/runtime/permissions.js.map +1 -0
  55. package/dist/runtime/pluginApi.d.ts +51 -2
  56. package/dist/runtime/pluginApi.js +137 -22
  57. package/dist/runtime/pluginApi.js.map +1 -1
  58. package/dist/runtime/pluginI18n.d.ts +29 -0
  59. package/dist/runtime/pluginI18n.js +119 -0
  60. package/dist/runtime/pluginI18n.js.map +1 -0
  61. package/dist/runtime/settingsForm.d.ts +66 -0
  62. package/dist/runtime/settingsForm.js +114 -0
  63. package/dist/runtime/settingsForm.js.map +1 -0
  64. package/dist/runtime/site.d.ts +5 -0
  65. package/dist/runtime/site.js +1 -1
  66. package/dist/runtime/site.js.map +1 -1
  67. package/dist/runtime/siteRuntime.d.ts +144 -0
  68. package/dist/runtime/siteRuntime.js +175 -0
  69. package/dist/runtime/siteRuntime.js.map +1 -0
  70. package/dist/runtime/stringPackHook.d.ts +84 -0
  71. package/dist/runtime/stringPackHook.js +220 -0
  72. package/dist/runtime/stringPackHook.js.map +1 -0
  73. package/dist/runtime/stringPackTranslate.d.ts +59 -0
  74. package/dist/runtime/stringPackTranslate.js +264 -0
  75. package/dist/runtime/stringPackTranslate.js.map +1 -0
  76. package/dist/runtime/stringPacks.d.ts +200 -0
  77. package/dist/runtime/stringPacks.js +474 -0
  78. package/dist/runtime/stringPacks.js.map +1 -0
  79. package/dist/runtime/styles.d.ts +15 -0
  80. package/dist/runtime/styles.js +81 -0
  81. package/dist/runtime/styles.js.map +1 -0
  82. package/dist/runtime/textNet.d.ts +15 -0
  83. package/dist/runtime/textNet.js +131 -0
  84. package/dist/runtime/textNet.js.map +1 -0
  85. package/dist/runtime/themeApi.d.ts +121 -0
  86. package/dist/runtime/themeApi.js +220 -0
  87. package/dist/runtime/themeApi.js.map +1 -0
  88. package/dist/runtime/themeChoice.d.ts +52 -0
  89. package/dist/runtime/themeChoice.js +69 -0
  90. package/dist/runtime/themeChoice.js.map +1 -0
  91. package/dist/runtime/themeComponents.d.ts +435 -0
  92. package/dist/runtime/themeComponents.js +463 -0
  93. package/dist/runtime/themeComponents.js.map +1 -0
  94. package/dist/runtime/themeDecor.d.ts +73 -0
  95. package/dist/runtime/themeDecor.js +131 -0
  96. package/dist/runtime/themeDecor.js.map +1 -0
  97. package/dist/runtime/themeDoctor.d.ts +11 -0
  98. package/dist/runtime/themeDoctor.js +51 -0
  99. package/dist/runtime/themeDoctor.js.map +1 -0
  100. package/dist/runtime/themeIcons.d.ts +130 -0
  101. package/dist/runtime/themeIcons.js +263 -0
  102. package/dist/runtime/themeIcons.js.map +1 -0
  103. package/dist/runtime/themeRuntime.d.ts +100 -0
  104. package/dist/runtime/themeRuntime.js +497 -0
  105. package/dist/runtime/themeRuntime.js.map +1 -0
  106. package/dist/runtime/themeSchema.d.ts +10 -0
  107. package/dist/runtime/themeSchema.js +150 -0
  108. package/dist/runtime/themeSchema.js.map +1 -0
  109. package/dist/runtime/themeSpec.d.ts +259 -0
  110. package/dist/runtime/themeSpec.js +439 -0
  111. package/dist/runtime/themeSpec.js.map +1 -0
  112. package/dist/runtime/themeTokens.d.ts +12 -0
  113. package/dist/runtime/themeTokens.js +14 -6
  114. package/dist/runtime/themeTokens.js.map +1 -1
  115. package/dist/runtime/themeVariants.d.ts +30 -0
  116. package/dist/runtime/themeVariants.js +53 -0
  117. package/dist/runtime/themeVariants.js.map +1 -0
  118. package/dist/runtime/ui.d.ts +192 -0
  119. package/dist/runtime/ui.js +926 -0
  120. package/dist/runtime/ui.js.map +1 -0
  121. package/dist/shell/InstallDialog.d.ts +40 -0
  122. package/dist/shell/InstallDialog.js +170 -0
  123. package/dist/shell/InstallDialog.js.map +1 -0
  124. package/dist/shell/StoreView.d.ts +66 -0
  125. package/dist/shell/StoreView.js +103 -0
  126. package/dist/shell/StoreView.js.map +1 -0
  127. package/dist/shell/addressModel.js.map +1 -1
  128. package/dist/shell/chrome.js.map +1 -1
  129. package/dist/shell/deckModel.d.ts +117 -0
  130. package/dist/shell/deckModel.js +267 -0
  131. package/dist/shell/deckModel.js.map +1 -0
  132. package/dist/shell/frame/AccountSwitcher.d.ts +42 -0
  133. package/dist/shell/frame/AccountSwitcher.js +243 -0
  134. package/dist/shell/frame/AccountSwitcher.js.map +1 -0
  135. package/dist/shell/frame/AddColumnDialog.d.ts +8 -0
  136. package/dist/shell/frame/AddColumnDialog.js +81 -0
  137. package/dist/shell/frame/AddColumnDialog.js.map +1 -0
  138. package/dist/shell/frame/AppMenu.d.ts +21 -0
  139. package/dist/shell/frame/AppMenu.js +642 -0
  140. package/dist/shell/frame/AppMenu.js.map +1 -0
  141. package/dist/shell/frame/CommandPalette.d.ts +7 -0
  142. package/dist/shell/frame/CommandPalette.js +118 -0
  143. package/dist/shell/frame/CommandPalette.js.map +1 -0
  144. package/dist/shell/frame/DeckView.d.ts +13 -0
  145. package/dist/shell/frame/DeckView.js +287 -0
  146. package/dist/shell/frame/DeckView.js.map +1 -0
  147. package/dist/shell/frame/FindBar.d.ts +10 -0
  148. package/dist/shell/frame/FindBar.js +108 -0
  149. package/dist/shell/frame/FindBar.js.map +1 -0
  150. package/dist/shell/frame/MediaPanel.d.ts +8 -0
  151. package/dist/shell/frame/MediaPanel.js +76 -0
  152. package/dist/shell/frame/MediaPanel.js.map +1 -0
  153. package/dist/shell/frame/NewTabPage.d.ts +9 -0
  154. package/dist/shell/frame/NewTabPage.js +71 -0
  155. package/dist/shell/frame/NewTabPage.js.map +1 -0
  156. package/dist/shell/frame/PaneTheme.d.ts +16 -0
  157. package/dist/shell/frame/PaneTheme.js +67 -0
  158. package/dist/shell/frame/PaneTheme.js.map +1 -0
  159. package/dist/shell/frame/ReportDialog.d.ts +3 -0
  160. package/dist/shell/frame/ReportDialog.js +95 -0
  161. package/dist/shell/frame/ReportDialog.js.map +1 -0
  162. package/dist/shell/frame/Shell.d.ts +8 -0
  163. package/dist/shell/frame/Shell.js +1131 -0
  164. package/dist/shell/frame/Shell.js.map +1 -0
  165. package/dist/shell/frame/Titlebar.d.ts +16 -0
  166. package/dist/shell/frame/Titlebar.js +77 -0
  167. package/dist/shell/frame/Titlebar.js.map +1 -0
  168. package/dist/shell/frame/TitlebarExtras.d.ts +4 -0
  169. package/dist/shell/frame/TitlebarExtras.js +202 -0
  170. package/dist/shell/frame/TitlebarExtras.js.map +1 -0
  171. package/dist/shell/frame/WebPanel.d.ts +4 -0
  172. package/dist/shell/frame/WebPanel.js +182 -0
  173. package/dist/shell/frame/WebPanel.js.map +1 -0
  174. package/dist/shell/frame/accountModel.d.ts +49 -0
  175. package/dist/shell/frame/accountModel.js +67 -0
  176. package/dist/shell/frame/accountModel.js.map +1 -0
  177. package/dist/shell/frame/accountSwitcher.css +91 -0
  178. package/dist/shell/frame/appI18n.d.ts +44 -0
  179. package/dist/shell/frame/appI18n.js +64 -0
  180. package/dist/shell/frame/appI18n.js.map +1 -0
  181. package/dist/shell/frame/appMenu.css +121 -0
  182. package/dist/shell/frame/backupModel.d.ts +38 -0
  183. package/dist/shell/frame/backupModel.js +192 -0
  184. package/dist/shell/frame/backupModel.js.map +1 -0
  185. package/dist/shell/frame/boot.d.ts +8 -0
  186. package/dist/shell/frame/boot.js +35 -0
  187. package/dist/shell/frame/boot.js.map +1 -0
  188. package/dist/shell/frame/brand.d.ts +1 -0
  189. package/dist/shell/frame/brand.js +4 -0
  190. package/dist/shell/frame/brand.js.map +1 -0
  191. package/dist/shell/frame/bridge.d.ts +35 -0
  192. package/dist/shell/frame/bridge.js +70 -0
  193. package/dist/shell/frame/bridge.js.map +1 -0
  194. package/dist/shell/frame/chromeTheme.d.ts +29 -0
  195. package/dist/shell/frame/chromeTheme.js +81 -0
  196. package/dist/shell/frame/chromeTheme.js.map +1 -0
  197. package/dist/shell/frame/deck.css +209 -0
  198. package/dist/shell/frame/deckStore.d.ts +89 -0
  199. package/dist/shell/frame/deckStore.js +239 -0
  200. package/dist/shell/frame/deckStore.js.map +1 -0
  201. package/dist/shell/frame/devHost.d.ts +35 -0
  202. package/dist/shell/frame/devHost.js +80 -0
  203. package/dist/shell/frame/devHost.js.map +1 -0
  204. package/dist/shell/frame/devModel.d.ts +7 -0
  205. package/dist/shell/frame/devModel.js +17 -0
  206. package/dist/shell/frame/devModel.js.map +1 -0
  207. package/dist/shell/frame/diag.d.ts +7 -0
  208. package/dist/shell/frame/diag.js +39 -0
  209. package/dist/shell/frame/diag.js.map +1 -0
  210. package/dist/shell/frame/findBar.css +14 -0
  211. package/dist/shell/frame/frameMessages.d.ts +248 -0
  212. package/dist/shell/frame/frameMessages.js +252 -0
  213. package/dist/shell/frame/frameMessages.js.map +1 -0
  214. package/dist/shell/frame/hooks.d.ts +39 -0
  215. package/dist/shell/frame/hooks.js +97 -0
  216. package/dist/shell/frame/hooks.js.map +1 -0
  217. package/dist/shell/frame/i18n.d.ts +27 -0
  218. package/dist/shell/frame/i18n.js +66 -0
  219. package/dist/shell/frame/i18n.js.map +1 -0
  220. package/dist/shell/frame/iconPack.d.ts +11 -0
  221. package/dist/shell/frame/iconPack.js +45 -0
  222. package/dist/shell/frame/iconPack.js.map +1 -0
  223. package/dist/shell/frame/icons.d.ts +71 -0
  224. package/dist/shell/frame/icons.js +75 -0
  225. package/dist/shell/frame/icons.js.map +1 -0
  226. package/dist/shell/frame/index.d.ts +34 -0
  227. package/dist/shell/frame/index.js +43 -0
  228. package/dist/shell/frame/index.js.map +1 -0
  229. package/dist/shell/frame/language.d.ts +58 -0
  230. package/dist/shell/frame/language.js +165 -0
  231. package/dist/shell/frame/language.js.map +1 -0
  232. package/dist/shell/frame/mediaModel.d.ts +34 -0
  233. package/dist/shell/frame/mediaModel.js +53 -0
  234. package/dist/shell/frame/mediaModel.js.map +1 -0
  235. package/dist/shell/frame/menuMessages.en.json +54 -0
  236. package/dist/shell/frame/menuModel.d.ts +277 -0
  237. package/dist/shell/frame/menuModel.js +293 -0
  238. package/dist/shell/frame/menuModel.js.map +1 -0
  239. package/dist/shell/frame/paletteModel.d.ts +139 -0
  240. package/dist/shell/frame/paletteModel.js +112 -0
  241. package/dist/shell/frame/paletteModel.js.map +1 -0
  242. package/dist/shell/frame/paneTheme.css +9 -0
  243. package/dist/shell/frame/pluginCommandStore.d.ts +23 -0
  244. package/dist/shell/frame/pluginCommandStore.js +70 -0
  245. package/dist/shell/frame/pluginCommandStore.js.map +1 -0
  246. package/dist/shell/frame/reportModel.d.ts +52 -0
  247. package/dist/shell/frame/reportModel.js +105 -0
  248. package/dist/shell/frame/reportModel.js.map +1 -0
  249. package/dist/shell/frame/safeStore.d.ts +7 -0
  250. package/dist/shell/frame/safeStore.js +40 -0
  251. package/dist/shell/frame/safeStore.js.map +1 -0
  252. package/dist/shell/frame/searchInput.d.ts +2 -0
  253. package/dist/shell/frame/searchInput.js +11 -0
  254. package/dist/shell/frame/searchInput.js.map +1 -0
  255. package/dist/shell/frame/shell.css +629 -0
  256. package/dist/shell/frame/site.d.ts +206 -0
  257. package/dist/shell/frame/site.js +22 -0
  258. package/dist/shell/frame/site.js.map +1 -0
  259. package/dist/shell/frame/state.d.ts +99 -0
  260. package/dist/shell/frame/state.js +284 -0
  261. package/dist/shell/frame/state.js.map +1 -0
  262. package/dist/shell/frame/syncGate.d.ts +10 -0
  263. package/dist/shell/frame/syncGate.js +36 -0
  264. package/dist/shell/frame/syncGate.js.map +1 -0
  265. package/dist/shell/frame/syncHost.d.ts +35 -0
  266. package/dist/shell/frame/syncHost.js +85 -0
  267. package/dist/shell/frame/syncHost.js.map +1 -0
  268. package/dist/shell/frame/tabStill.d.ts +2 -0
  269. package/dist/shell/frame/tabStill.js +62 -0
  270. package/dist/shell/frame/tabStill.js.map +1 -0
  271. package/dist/shell/frame/themeScopes.d.ts +29 -0
  272. package/dist/shell/frame/themeScopes.js +61 -0
  273. package/dist/shell/frame/themeScopes.js.map +1 -0
  274. package/dist/shell/frame/themeStore.d.ts +99 -0
  275. package/dist/shell/frame/themeStore.js +252 -0
  276. package/dist/shell/frame/themeStore.js.map +1 -0
  277. package/dist/shell/frame/windowBinding.d.ts +2 -0
  278. package/dist/shell/frame/windowBinding.js +7 -0
  279. package/dist/shell/frame/windowBinding.js.map +1 -0
  280. package/dist/shell/frame/workspaceModel.d.ts +82 -0
  281. package/dist/shell/frame/workspaceModel.js +250 -0
  282. package/dist/shell/frame/workspaceModel.js.map +1 -0
  283. package/dist/shell/frame/workspaces.css +84 -0
  284. package/dist/shell/frame/workspaces.d.ts +22 -0
  285. package/dist/shell/frame/workspaces.js +125 -0
  286. package/dist/shell/frame/workspaces.js.map +1 -0
  287. package/dist/shell/frame/zoomStore.d.ts +10 -0
  288. package/dist/shell/frame/zoomStore.js +65 -0
  289. package/dist/shell/frame/zoomStore.js.map +1 -0
  290. package/dist/shell/installController.d.ts +122 -0
  291. package/dist/shell/installController.js +146 -0
  292. package/dist/shell/installController.js.map +1 -0
  293. package/dist/shell/installerMessages.d.ts +30 -0
  294. package/dist/shell/installerMessages.js +36 -0
  295. package/dist/shell/installerMessages.js.map +1 -0
  296. package/dist/shell/linkDrop.js.map +1 -1
  297. package/dist/shell/messages.d.ts +16 -0
  298. package/dist/shell/messages.js +27 -0
  299. package/dist/shell/messages.js.map +1 -0
  300. package/dist/shell/palette.js.map +1 -1
  301. package/dist/shell/paneModel.d.ts +22 -0
  302. package/dist/shell/paneModel.js +24 -1
  303. package/dist/shell/paneModel.js.map +1 -1
  304. package/dist/shell/panel/Appearance.d.ts +8 -0
  305. package/dist/shell/panel/Appearance.js +256 -0
  306. package/dist/shell/panel/Appearance.js.map +1 -0
  307. package/dist/shell/panel/BackupPanel.d.ts +5 -0
  308. package/dist/shell/panel/BackupPanel.js +198 -0
  309. package/dist/shell/panel/BackupPanel.js.map +1 -0
  310. package/dist/shell/panel/DeveloperPanel.d.ts +4 -0
  311. package/dist/shell/panel/DeveloperPanel.js +51 -0
  312. package/dist/shell/panel/DeveloperPanel.js.map +1 -0
  313. package/dist/shell/panel/FeatureToggles.d.ts +13 -0
  314. package/dist/shell/panel/FeatureToggles.js +42 -0
  315. package/dist/shell/panel/FeatureToggles.js.map +1 -0
  316. package/dist/shell/panel/Home.d.ts +3 -0
  317. package/dist/shell/panel/Home.js +23 -0
  318. package/dist/shell/panel/Home.js.map +1 -0
  319. package/dist/shell/panel/IconPackInstall.d.ts +15 -0
  320. package/dist/shell/panel/IconPackInstall.js +41 -0
  321. package/dist/shell/panel/IconPackInstall.js.map +1 -0
  322. package/dist/shell/panel/LanguageSettings.d.ts +1 -0
  323. package/dist/shell/panel/LanguageSettings.js +54 -0
  324. package/dist/shell/panel/LanguageSettings.js.map +1 -0
  325. package/dist/shell/panel/MakePanel.d.ts +3 -0
  326. package/dist/shell/panel/MakePanel.js +237 -0
  327. package/dist/shell/panel/MakePanel.js.map +1 -0
  328. package/dist/shell/panel/MarkdownDoc.d.ts +6 -0
  329. package/dist/shell/panel/MarkdownDoc.js +35 -0
  330. package/dist/shell/panel/MarkdownDoc.js.map +1 -0
  331. package/dist/shell/panel/Modes.d.ts +40 -0
  332. package/dist/shell/panel/Modes.js +270 -0
  333. package/dist/shell/panel/Modes.js.map +1 -0
  334. package/dist/shell/panel/NavIcon.d.ts +4 -0
  335. package/dist/shell/panel/NavIcon.js +6 -0
  336. package/dist/shell/panel/NavIcon.js.map +1 -0
  337. package/dist/shell/panel/Panel.d.ts +7 -0
  338. package/dist/shell/panel/Panel.js +139 -0
  339. package/dist/shell/panel/Panel.js.map +1 -0
  340. package/dist/shell/panel/PluginFeatures.d.ts +24 -0
  341. package/dist/shell/panel/PluginFeatures.js +165 -0
  342. package/dist/shell/panel/PluginFeatures.js.map +1 -0
  343. package/dist/shell/panel/Plugins.d.ts +33 -0
  344. package/dist/shell/panel/Plugins.js +112 -0
  345. package/dist/shell/panel/Plugins.js.map +1 -0
  346. package/dist/shell/panel/PowerSettings.d.ts +4 -0
  347. package/dist/shell/panel/PowerSettings.js +52 -0
  348. package/dist/shell/panel/PowerSettings.js.map +1 -0
  349. package/dist/shell/panel/Settings.d.ts +23 -0
  350. package/dist/shell/panel/Settings.js +116 -0
  351. package/dist/shell/panel/Settings.js.map +1 -0
  352. package/dist/shell/panel/ShareSetup.d.ts +8 -0
  353. package/dist/shell/panel/ShareSetup.js +130 -0
  354. package/dist/shell/panel/ShareSetup.js.map +1 -0
  355. package/dist/shell/panel/StoreSection.d.ts +6 -0
  356. package/dist/shell/panel/StoreSection.js +48 -0
  357. package/dist/shell/panel/StoreSection.js.map +1 -0
  358. package/dist/shell/panel/StringPacks.d.ts +11 -0
  359. package/dist/shell/panel/StringPacks.js +106 -0
  360. package/dist/shell/panel/StringPacks.js.map +1 -0
  361. package/dist/shell/panel/ThemeBuilder.d.ts +5 -0
  362. package/dist/shell/panel/ThemeBuilder.js +205 -0
  363. package/dist/shell/panel/ThemeBuilder.js.map +1 -0
  364. package/dist/shell/panel/backup.css +34 -0
  365. package/dist/shell/panel/builder.css +232 -0
  366. package/dist/shell/panel/builderModel.d.ts +55 -0
  367. package/dist/shell/panel/builderModel.js +95 -0
  368. package/dist/shell/panel/builderModel.js.map +1 -0
  369. package/dist/shell/panel/compare.d.ts +10 -0
  370. package/dist/shell/panel/compare.js +51 -0
  371. package/dist/shell/panel/compare.js.map +1 -0
  372. package/dist/shell/panel/controls.d.ts +135 -0
  373. package/dist/shell/panel/controls.js +213 -0
  374. package/dist/shell/panel/controls.js.map +1 -0
  375. package/dist/shell/panel/featureModel.d.ts +69 -0
  376. package/dist/shell/panel/featureModel.js +79 -0
  377. package/dist/shell/panel/featureModel.js.map +1 -0
  378. package/dist/shell/panel/fonts/FontBrowser.d.ts +10 -0
  379. package/dist/shell/panel/fonts/FontBrowser.js +189 -0
  380. package/dist/shell/panel/fonts/FontBrowser.js.map +1 -0
  381. package/dist/shell/panel/fonts/FontRoles.d.ts +20 -0
  382. package/dist/shell/panel/fonts/FontRoles.js +77 -0
  383. package/dist/shell/panel/fonts/FontRoles.js.map +1 -0
  384. package/dist/shell/panel/fonts/catalog.d.ts +37 -0
  385. package/dist/shell/panel/fonts/catalog.js +68 -0
  386. package/dist/shell/panel/fonts/catalog.js.map +1 -0
  387. package/dist/shell/panel/fonts/googleFontsCatalog.json +1 -0
  388. package/dist/shell/panel/index.d.ts +20 -0
  389. package/dist/shell/panel/index.js +34 -0
  390. package/dist/shell/panel/index.js.map +1 -0
  391. package/dist/shell/panel/languageModel.d.ts +5 -0
  392. package/dist/shell/panel/languageModel.js +7 -0
  393. package/dist/shell/panel/languageModel.js.map +1 -0
  394. package/dist/shell/panel/make.css +72 -0
  395. package/dist/shell/panel/makeModel.d.ts +32 -0
  396. package/dist/shell/panel/makeModel.js +84 -0
  397. package/dist/shell/panel/makeModel.js.map +1 -0
  398. package/dist/shell/panel/markdown.d.ts +46 -0
  399. package/dist/shell/panel/markdown.js +100 -0
  400. package/dist/shell/panel/markdown.js.map +1 -0
  401. package/dist/shell/panel/nav.d.ts +12 -0
  402. package/dist/shell/panel/nav.js +50 -0
  403. package/dist/shell/panel/nav.js.map +1 -0
  404. package/dist/shell/panel/panel.css +401 -0
  405. package/dist/shell/panel/panelMessages.d.ts +763 -0
  406. package/dist/shell/panel/panelMessages.js +767 -0
  407. package/dist/shell/panel/panelMessages.js.map +1 -0
  408. package/dist/shell/panel/plugins.css +59 -0
  409. package/dist/shell/panel/setupModel.d.ts +87 -0
  410. package/dist/shell/panel/setupModel.js +152 -0
  411. package/dist/shell/panel/setupModel.js.map +1 -0
  412. package/dist/shell/panel/site.d.ts +259 -0
  413. package/dist/shell/panel/site.js +25 -0
  414. package/dist/shell/panel/site.js.map +1 -0
  415. package/dist/shell/panel/strings.css +7 -0
  416. package/dist/shell/panel/themes.d.ts +10 -0
  417. package/dist/shell/panel/themes.js +8 -0
  418. package/dist/shell/panel/themes.js.map +1 -0
  419. package/dist/shell/profileModel.d.ts +3 -2
  420. package/dist/shell/profileModel.js +7 -5
  421. package/dist/shell/profileModel.js.map +1 -1
  422. package/dist/shell/store.css +230 -0
  423. package/dist/shell/storeMessages.d.ts +169 -0
  424. package/dist/shell/storeMessages.js +172 -0
  425. package/dist/shell/storeMessages.js.map +1 -0
  426. package/dist/shell/storeModel.d.ts +181 -0
  427. package/dist/shell/storeModel.js +133 -0
  428. package/dist/shell/storeModel.js.map +1 -0
  429. package/dist/shell/stringPacksModel.d.ts +44 -0
  430. package/dist/shell/stringPacksModel.js +94 -0
  431. package/dist/shell/stringPacksModel.js.map +1 -0
  432. package/dist/shell/updateModel.d.ts +2 -1
  433. package/dist/shell/updateModel.js +5 -4
  434. package/dist/shell/updateModel.js.map +1 -1
  435. package/dist/shell/windowControls.d.ts +4 -0
  436. package/dist/shell/windowControls.js +5 -0
  437. package/dist/shell/windowControls.js.map +1 -1
  438. package/i18n-config.schema.json +29 -0
  439. package/i18n-meta.schema.json +26 -0
  440. package/i18n.schema.json +42 -0
  441. package/icons.schema.json +646 -0
  442. package/languages.schema.json +23 -0
  443. package/locales/ar-x-fm.json +11 -0
  444. package/locales/ar.json +1281 -0
  445. package/locales/bg.json +1280 -0
  446. package/locales/bn.json +1280 -0
  447. package/locales/ca.json +1280 -0
  448. package/locales/cs.json +1280 -0
  449. package/locales/da.json +1280 -0
  450. package/locales/de.json +1280 -0
  451. package/locales/el.json +1280 -0
  452. package/locales/en-GB.json +27 -0
  453. package/locales/en.json +1280 -0
  454. package/locales/en.meta.json +51 -0
  455. package/locales/es.json +1280 -0
  456. package/locales/eu.json +1280 -0
  457. package/locales/fa.json +1281 -0
  458. package/locales/fi.json +1280 -0
  459. package/locales/fil.json +1280 -0
  460. package/locales/fr.json +1280 -0
  461. package/locales/ga.json +1280 -0
  462. package/locales/gl.json +1280 -0
  463. package/locales/gu.json +1280 -0
  464. package/locales/ha.json +1280 -0
  465. package/locales/he.json +1281 -0
  466. package/locales/hi.json +1280 -0
  467. package/locales/hr.json +1280 -0
  468. package/locales/hu.json +1279 -0
  469. package/locales/id.json +1280 -0
  470. package/locales/ig.json +1280 -0
  471. package/locales/it.json +1280 -0
  472. package/locales/ja.json +1280 -0
  473. package/locales/kn.json +1280 -0
  474. package/locales/ko.json +1280 -0
  475. package/locales/mr.json +1280 -0
  476. package/locales/ms.json +1280 -0
  477. package/locales/nb.json +1280 -0
  478. package/locales/nl.json +1280 -0
  479. package/locales/pl.json +1280 -0
  480. package/locales/pt.json +1280 -0
  481. package/locales/ro.json +1280 -0
  482. package/locales/ru.json +1280 -0
  483. package/locales/sk.json +1280 -0
  484. package/locales/sr.json +1280 -0
  485. package/locales/sv.json +1280 -0
  486. package/locales/ta.json +1280 -0
  487. package/locales/th.json +1280 -0
  488. package/locales/tr.json +1280 -0
  489. package/locales/uk.json +1280 -0
  490. package/locales/ur.json +1281 -0
  491. package/locales/vi.json +1280 -0
  492. package/locales/yo.json +1280 -0
  493. package/locales/zh-Hans.json +1280 -0
  494. package/locales/zh-Hant.json +1280 -0
  495. package/package.json +139 -5
  496. package/store-catalog.schema.json +65 -0
  497. package/theme.schema.json +4659 -0
  498. package/windows/installer.nsi +926 -0
  499. package/windows/languages/Basque.nsh +28 -0
  500. package/windows/languages/Catalan.nsh +28 -0
  501. package/windows/languages/Croatian.nsh +28 -0
  502. package/windows/languages/Czech.nsh +28 -0
  503. package/windows/languages/Danish.nsh +28 -0
  504. package/windows/languages/Finnish.nsh +28 -0
  505. package/windows/languages/Galician.nsh +28 -0
  506. package/windows/languages/Greek.nsh +28 -0
  507. package/windows/languages/Hungarian.nsh +28 -0
  508. package/windows/languages/Indonesian.nsh +28 -0
  509. package/windows/languages/Irish.nsh +28 -0
  510. package/windows/languages/Malay.nsh +28 -0
  511. package/windows/languages/Polish.nsh +28 -0
  512. package/windows/languages/Romanian.nsh +28 -0
  513. package/windows/languages/Serbian.nsh +28 -0
  514. package/windows/languages/Slovak.nsh +28 -0
  515. package/windows/languages/Thai.nsh +28 -0
@@ -0,0 +1,484 @@
1
+ // Feature modules: the code side of the feature table (featureTable.ts). An app's area plugins
2
+ // ("Navigation+") are sets of small modules, one per feature; the registry starts a module only
3
+ // while its flag is on, its area's switch is on and the page is on one of its surfaces, and
4
+ // disposes everything it did when any of those stops being true. A hundred features then cost what
5
+ // the ones on screen cost:
6
+ //
7
+ // const registry = createFeatureRegistry({ win, table, api, label, surfaces, message });
8
+ // registry.define({ id: 'navigation.keyboardPlus', start(ctx) { ctx.onKey(...); } });
9
+ // registry.setFlags(effectiveFlags(table, flags)); // from the app's feature flags
10
+ //
11
+ // A module's `start(ctx)` gets a context whose every helper is undone on stop: CSS, listeners,
12
+ // nodes, DOM watching through the shared hub (one MutationObserver for every feature, domHub.ts),
13
+ // palette commands under its area's name, its words, its storage and its settings. A module with a
14
+ // `settings` schema gets a settings dialog drawn from the UI kit (settingsForm.ts); each area with
15
+ // such a feature gets one "settings" palette command.
16
+ //
17
+ // Health: a module names the selectors it depends on (`probes`). After the page has settled, a
18
+ // probe that matches nothing is a miss; three misses in a row (three visits) pause that one feature
19
+ // for the session, with one toast and a note in the settings dialog. The site's markup changed; the
20
+ // rest of the area keeps working. A signed hotfix may replace a probe's selector
21
+ // (`selectors["<feature id>.<probe>"]`) or switch a feature off (`flags["<feature id>"] = false`).
22
+ import { domRoots, hasShadowHosts, isHeavyPath, observeSelector, watchDom } from "./domHub.js";
23
+ import { adoptStyles } from "./styles.js";
24
+ import { HEALTH_COMMAND, areaFlag, healthKeywords } from "./featureTable.js";
25
+ import { formatMessage } from "./i18n.js";
26
+ import { buildSettingsForm, normalizeSettings, validateSchema } from "./settingsForm.js";
27
+ import { KIT_MESSAGES } from "./ui.js";
28
+ /** Palette commands one area may register: its "settings" entry and four actions (the tab reports at most 48). */
29
+ export const AREA_COMMAND_BUDGET = 5;
30
+ /** Misses in a row (separate visits) before a feature pauses itself. */
31
+ export const PROBE_STRIKES = 3;
32
+ const featureName = (id) => id.slice(id.indexOf('.') + 1);
33
+ export function createFeatureRegistry(options) {
34
+ const { win, table, api, label } = options;
35
+ const doc = win.document;
36
+ const timers = options.timers ?? { setTimeout: (fn, ms) => win.setTimeout(fn, ms), clearTimeout: (id) => win.clearTimeout(id) };
37
+ const settleMs = options.settleMs ?? 3000;
38
+ const pollMs = options.pollMs ?? 500;
39
+ const specs = new Map(table.features.map(feature => [feature.id, feature]));
40
+ const areas = new Map(table.areas.map(area => [area.id, area]));
41
+ const modules = new Map();
42
+ const running = new Map();
43
+ const areaScopes = new Map();
44
+ const healthScopes = new Map();
45
+ const strikes = new Map();
46
+ const paused = new Map();
47
+ const waiting = new Map();
48
+ let flags = {};
49
+ let stopRoutes = null;
50
+ let visit = 0;
51
+ // The registry's own words are the kit's (`kit.feature.*`, `kit.save`): English unless the app delivers them.
52
+ const text = (key, params = {}) => formatMessage(options.message?.(key) ?? KIT_MESSAGES[key], params, options.locale?.() ?? 'en');
53
+ const hotfix = () => { try {
54
+ return options.hotfix?.() ?? {};
55
+ }
56
+ catch {
57
+ return {};
58
+ } };
59
+ const english = () => options.english?.() ?? /^en\b/i.test(doc.documentElement?.getAttribute?.('lang') ?? 'en');
60
+ const settled = () => options.settled?.() ?? !!doc.body?.firstElementChild;
61
+ /** A selector matches in the page or in one of its configured open shadow roots. */
62
+ const inPage = (selector) => domRoots(doc.defaultView ?? { document: doc }).some(root => !!root.querySelector(selector));
63
+ const words = (area) => api.i18n.namespace(area.namespace);
64
+ /** A feature's word `key`: under its own namespace when it names one (`words`), else under its area's. */
65
+ const wordOf = (module, area, key, params) => (module.words ? api.i18n.namespace(module.words).t(key, params) : words(area).t(`${featureName(module.id)}.${key}`, params));
66
+ /** A feature's label in the page, when the page has it (`plugin.*` words only reach a site tab). */
67
+ const featureLabel = (spec, area) => {
68
+ const legacy = modules.get(spec.id)?.words;
69
+ if (legacy) {
70
+ const own = api.i18n.namespace(legacy);
71
+ return own.has('name') ? own.t('name') : null;
72
+ }
73
+ const i18n = words(area);
74
+ const key = `feature.${featureName(spec.id)}.label`;
75
+ return i18n.has(key) ? i18n.t(key) : null;
76
+ };
77
+ const selectorOf = (module, name) => {
78
+ const override = hotfix().selectors?.[`${module.id}.${name}`];
79
+ if (typeof override === 'string' && override.trim())
80
+ return override;
81
+ const probe = module.probes?.[name];
82
+ if (probe === undefined)
83
+ throw new Error(`${module.id}: no probe named ${JSON.stringify(name)}`);
84
+ return typeof probe === 'string' ? probe : probe.selector;
85
+ };
86
+ function wanted(module) {
87
+ const spec = specs.get(module.id);
88
+ if (flags[module.id] !== true || paused.has(module.id) || hotfix().flags?.[module.id] === false)
89
+ return false;
90
+ if (!spec.heavy && isHeavyPath(win.location.pathname ?? ''))
91
+ return false;
92
+ if (!spec.surfaces?.length)
93
+ return true;
94
+ const on = options.surfaces();
95
+ return spec.surfaces.some(surface => on.includes(surface));
96
+ }
97
+ function settingsOf(module, area, listeners) {
98
+ const schema = module.settings ?? [];
99
+ const store = () => api.storage(module.storage ?? `${area.namespace}.${featureName(module.id)}`);
100
+ const key = module.settingsKey ?? 'settings';
101
+ const get = () => normalizeSettings(schema, store().get(key, null));
102
+ return {
103
+ get,
104
+ set(patch) {
105
+ const next = normalizeSettings(schema, { ...get(), ...patch });
106
+ const saved = store().set(key, next);
107
+ for (const listener of [...listeners]) {
108
+ try {
109
+ listener(next);
110
+ }
111
+ catch (error) {
112
+ console.error(`[${label}] ${module.id} settings listener failed`, error);
113
+ }
114
+ }
115
+ return saved;
116
+ },
117
+ onChange(callback) { listeners.add(callback); },
118
+ open() { openSettings(area.id, module.id); },
119
+ };
120
+ }
121
+ function start(module) {
122
+ const spec = specs.get(module.id);
123
+ const area = areas.get(spec.area);
124
+ const scope = api.commands.withOwner(area.owner, () => api.scope());
125
+ const listeners = new Set();
126
+ const entry = { module, spec, area, scope, commands: 0, listeners, settings: settingsOf(module, area, listeners), visit: -1, timer: null };
127
+ const name = featureName(module.id);
128
+ const domWin = win;
129
+ const styles = new Set();
130
+ // The same sheets, adopted by each configured open shadow root of the page (a site part rendered
131
+ // inside one, e.g. X's chat embed); roots that appear later get them on the next hub frame.
132
+ const rootCss = new Map();
133
+ const rootSheets = new Map();
134
+ let rootWatch = null;
135
+ const syncRoots = () => {
136
+ const roots = domRoots(domWin).slice(1);
137
+ for (const [root, sheets] of rootSheets) {
138
+ if (roots.includes(root))
139
+ continue;
140
+ for (const item of sheets.values())
141
+ item.sheet.remove();
142
+ rootSheets.delete(root);
143
+ }
144
+ for (const root of roots) {
145
+ let sheets = rootSheets.get(root);
146
+ if (!sheets) {
147
+ sheets = new Map();
148
+ rootSheets.set(root, sheets);
149
+ }
150
+ for (const [styleId, item] of sheets)
151
+ if (!rootCss.has(styleId)) {
152
+ item.sheet.remove();
153
+ sheets.delete(styleId);
154
+ }
155
+ for (const [styleId, css] of rootCss) {
156
+ const item = sheets.get(styleId);
157
+ if (!item)
158
+ sheets.set(styleId, { sheet: adoptStyles(root, css), css });
159
+ else if (item.css !== css) {
160
+ item.sheet.update(css);
161
+ item.css = css;
162
+ }
163
+ }
164
+ }
165
+ };
166
+ const ctx = {
167
+ id: module.id,
168
+ name,
169
+ area,
170
+ api,
171
+ win,
172
+ css(css, part = '') {
173
+ const styleId = `wbf-${module.id}${part ? `-${part}` : ''}`;
174
+ if (!styles.has(styleId)) {
175
+ styles.add(styleId);
176
+ scope.defer(() => api.clearCSS(styleId));
177
+ }
178
+ if (css)
179
+ api.injectCSS(styleId, css);
180
+ else
181
+ api.clearCSS(styleId);
182
+ if (css)
183
+ rootCss.set(styleId, css);
184
+ else
185
+ rootCss.delete(styleId);
186
+ if (!rootWatch && css && hasShadowHosts()) {
187
+ rootWatch = watchDom(domWin, syncRoots, { offOnHeavy: !spec.heavy });
188
+ scope.defer(() => {
189
+ rootWatch?.dispose();
190
+ rootWatch = null;
191
+ rootCss.clear();
192
+ for (const sheets of rootSheets.values())
193
+ for (const item of sheets.values())
194
+ item.sheet.remove();
195
+ rootSheets.clear();
196
+ });
197
+ }
198
+ if (rootWatch)
199
+ syncRoots();
200
+ },
201
+ observe(selector, callback) {
202
+ scope.defer(observeSelector(domWin, selector, callback, { offOnHeavy: !spec.heavy, report: error => console.error(`[${label}] ${module.id} failed`, error) }));
203
+ },
204
+ watch(run, watchOptions = {}) {
205
+ const handle = watchDom(domWin, run, { offOnHeavy: !spec.heavy, ...watchOptions });
206
+ scope.defer(() => handle.dispose());
207
+ return handle;
208
+ },
209
+ on: (target, type, listener, listenerOptions) => scope.on(target, type, listener, listenerOptions),
210
+ onKey: callback => scope.onKey(callback),
211
+ onRouteChange: callback => scope.onRouteChange(callback),
212
+ add: node => scope.add(node),
213
+ defer: fn => scope.defer(fn),
214
+ get ui() { return scope.ui; },
215
+ command(definition) {
216
+ const reserved = table.features.some(feature => feature.area === area.id && feature.settings) ? 1 : 0;
217
+ const used = [...running.values()].filter(other => other.area.id === area.id).reduce((sum, other) => sum + other.commands, 0);
218
+ if (used + reserved >= AREA_COMMAND_BUDGET)
219
+ throw new Error(`${area.name}: at most ${AREA_COMMAND_BUDGET} palette commands per area`);
220
+ scope.commands.register(definition);
221
+ entry.commands += 1;
222
+ },
223
+ text: (key, params) => wordOf(module, area, key, params),
224
+ get storage() { return api.storage(module.storage ?? `${area.namespace}.${name}`); },
225
+ settings: entry.settings,
226
+ selector: probe => selectorOf(module, probe),
227
+ surfaces: () => options.surfaces(),
228
+ };
229
+ running.set(module.id, entry);
230
+ try {
231
+ module.start(ctx);
232
+ }
233
+ catch (error) {
234
+ console.error(`[${label}] ${module.id} failed`, error);
235
+ stop(module.id);
236
+ return;
237
+ }
238
+ scheduleProbes(entry);
239
+ }
240
+ function stop(id) {
241
+ const entry = running.get(id);
242
+ if (!entry)
243
+ return;
244
+ running.delete(id);
245
+ if (entry.timer !== null)
246
+ timers.clearTimeout(entry.timer);
247
+ entry.listeners.clear();
248
+ entry.scope.dispose();
249
+ }
250
+ // ---- Health ----------------------------------------------------------------------------------
251
+ function scheduleProbes(entry) {
252
+ if (!entry.module.probes || !Object.keys(entry.module.probes).length || entry.visit === visit)
253
+ return;
254
+ entry.visit = visit;
255
+ if (entry.timer !== null)
256
+ timers.clearTimeout(entry.timer);
257
+ const mine = visit;
258
+ let tries = 0;
259
+ const waitForSettle = () => {
260
+ entry.timer = null;
261
+ if (running.get(entry.module.id) !== entry || mine !== visit)
262
+ return;
263
+ if (!settled()) {
264
+ tries += 1;
265
+ // A page that never settles (an error page, a sign-in wall) is no verdict.
266
+ if (tries <= 20)
267
+ entry.timer = timers.setTimeout(waitForSettle, pollMs);
268
+ return;
269
+ }
270
+ entry.timer = timers.setTimeout(judge, settleMs);
271
+ };
272
+ const judge = () => {
273
+ entry.timer = null;
274
+ if (running.get(entry.module.id) !== entry || mine !== visit)
275
+ return;
276
+ const id = entry.module.id;
277
+ const missing = [];
278
+ const needEnglish = [];
279
+ const inEnglish = english();
280
+ for (const [name, probe] of Object.entries(entry.module.probes ?? {})) {
281
+ if (typeof probe !== 'string' && probe.english && !inEnglish) {
282
+ needEnglish.push(name);
283
+ continue;
284
+ }
285
+ if (typeof probe !== 'string' && probe.when) {
286
+ let there = false;
287
+ try {
288
+ there = inPage(probe.when);
289
+ }
290
+ catch {
291
+ there = false;
292
+ }
293
+ if (!there)
294
+ continue;
295
+ }
296
+ let found = false;
297
+ try {
298
+ found = inPage(selectorOf(entry.module, name));
299
+ }
300
+ catch {
301
+ found = false;
302
+ }
303
+ if (!found)
304
+ missing.push(name);
305
+ }
306
+ if (needEnglish.length)
307
+ waiting.set(id, needEnglish);
308
+ else
309
+ waiting.delete(id);
310
+ if (!missing.length) {
311
+ strikes.delete(id);
312
+ return;
313
+ }
314
+ const count = (strikes.get(id) ?? 0) + 1;
315
+ strikes.set(id, count);
316
+ if (count < PROBE_STRIKES)
317
+ return;
318
+ paused.set(id, missing);
319
+ stop(id);
320
+ syncAreas();
321
+ console.warn(`[${label}] ${id} paused: nothing matches ${missing.join(', ')}`);
322
+ const feature = featureLabel(entry.spec, entry.area);
323
+ try {
324
+ api.ui.toast(feature ? text('kit.feature.paused', { feature, area: entry.area.name }) : text('kit.feature.pausedOne', { area: entry.area.name }), { tone: 'warning', duration: 8000 });
325
+ }
326
+ catch { /* a page without a body yet: the note in the settings dialog remains */ }
327
+ };
328
+ entry.timer = timers.setTimeout(waitForSettle, pollMs);
329
+ }
330
+ // ---- Settings dialog and the area's command --------------------------------------------------
331
+ function openSettings(areaId, only) {
332
+ const area = areas.get(areaId);
333
+ if (!area)
334
+ return false;
335
+ const entries = [...running.values()].filter(entry => entry.area.id === areaId && entry.module.settings?.length && (!only || entry.module.id === only));
336
+ const notes = health().filter(note => note.area === areaId);
337
+ if (!entries.length && !notes.length)
338
+ return false;
339
+ const ui = api.ui;
340
+ const h = ui.h;
341
+ const forms = entries.map(entry => {
342
+ const name = featureName(entry.module.id);
343
+ return { entry, title: featureLabel(entry.spec, area) ?? name, form: buildSettingsForm(h, entry.module.settings, entry.settings.get(), key => wordOf(entry.module, area, key)) };
344
+ });
345
+ const single = forms.length === 1 && !notes.length ? forms[0] : null;
346
+ ui.dialog({
347
+ title: text('kit.feature.settings', { name: single ? single.title : area.name }),
348
+ content: body => {
349
+ forms.forEach((item, index) => {
350
+ if (index > 0)
351
+ body.append(h('div', { class: 'wb-divider' }));
352
+ if (!single)
353
+ body.append(h('p', { class: 'wb-label' }, item.title));
354
+ body.append(...item.form.nodes);
355
+ });
356
+ for (const note of notes) {
357
+ const spec = specs.get(note.id);
358
+ const feature = featureLabel(spec, area) ?? featureName(note.id);
359
+ body.append(h('p', { class: 'wb-hint' }, note.state === 'paused' ? text('kit.feature.paused', { feature, area: area.name }) : text('kit.feature.needsEnglish', { feature })));
360
+ }
361
+ },
362
+ actions: forms.length ? [
363
+ { label: text('kit.cancel') },
364
+ {
365
+ label: text('kit.save'), tone: 'primary', default: true,
366
+ onClick: handle => {
367
+ const failed = forms.filter(item => !item.entry.settings.set(item.form.read()));
368
+ if (failed.length) {
369
+ handle.setError(text('kit.failed'));
370
+ return false;
371
+ }
372
+ return undefined;
373
+ },
374
+ },
375
+ ] : undefined,
376
+ });
377
+ return true;
378
+ }
379
+ /** Each area with a running feature that has settings gets its one "settings" palette command. */
380
+ function syncAreas() {
381
+ for (const area of table.areas) {
382
+ const needs = [...running.values()].some(entry => entry.area.id === area.id && entry.module.settings?.length);
383
+ const scope = areaScopes.get(area.id);
384
+ if (needs && !scope) {
385
+ const created = api.commands.withOwner(area.owner, () => api.scope());
386
+ areaScopes.set(area.id, created);
387
+ try {
388
+ created.commands.register({ id: 'settings', title: text('kit.feature.settings', { name: area.name }), keywords: `settings options configure ${area.name}`, run: () => { openSettings(area.id); } });
389
+ }
390
+ catch (error) {
391
+ console.error(`[${label}] ${area.name} settings command failed`, error);
392
+ }
393
+ }
394
+ else if (!needs && scope) {
395
+ scope.dispose();
396
+ areaScopes.delete(area.id);
397
+ }
398
+ // A paused feature that would run (its flag and area are on) is named in the palette: the
399
+ // entry opens the notes, and the panel reads it for the feature's row (featureTable `pausedFeatures`).
400
+ const ids = [...paused.keys()].filter(id => specs.get(id).area === area.id && flags[id] === true).join(' ');
401
+ const shown = healthScopes.get(area.id);
402
+ if (shown && shown.ids !== ids) {
403
+ shown.scope.dispose();
404
+ healthScopes.delete(area.id);
405
+ }
406
+ if (ids && !healthScopes.has(area.id)) {
407
+ const created = api.commands.withOwner(area.owner, () => api.scope());
408
+ healthScopes.set(area.id, { scope: created, ids });
409
+ try {
410
+ created.commands.register({ id: HEALTH_COMMAND, title: text('kit.feature.pausedList', { area: area.name }), keywords: healthKeywords(ids.split(' ')), run: () => { openSettings(area.id); } });
411
+ }
412
+ catch (error) {
413
+ console.error(`[${label}] ${area.name} health command failed`, error);
414
+ }
415
+ }
416
+ }
417
+ }
418
+ function health() {
419
+ const out = [];
420
+ for (const [id, probes] of paused)
421
+ out.push({ id, area: specs.get(id).area, state: 'paused', probes });
422
+ for (const [id, probes] of waiting)
423
+ if (!paused.has(id))
424
+ out.push({ id, area: specs.get(id).area, state: 'needs-english', probes });
425
+ return out;
426
+ }
427
+ function refresh() {
428
+ for (const module of modules.values()) {
429
+ const on = running.has(module.id);
430
+ const want = wanted(module);
431
+ if (want && !on)
432
+ start(module);
433
+ else if (!want && on)
434
+ stop(module.id);
435
+ else if (want && on)
436
+ scheduleProbes(running.get(module.id));
437
+ }
438
+ syncAreas();
439
+ }
440
+ return {
441
+ define(module) {
442
+ const spec = specs.get(module.id);
443
+ if (!spec || spec.backing !== 'module' || spec.area === null || !areas.has(spec.area))
444
+ throw new Error(`${label}: ${module.id} is not a feature module in the table`);
445
+ if (modules.has(module.id))
446
+ throw new Error(`${label}: ${module.id} is defined twice`);
447
+ const problems = validateSchema(module.settings ?? []);
448
+ if (problems.length)
449
+ throw new Error(`${label}: ${module.id} settings: ${problems.join('; ')}`);
450
+ if (!!module.settings?.length !== !!spec.settings)
451
+ throw new Error(`${label}: ${module.id}: the table's "settings" and the module's schema disagree`);
452
+ modules.set(module.id, module);
453
+ stopRoutes ??= api.onRouteChange(() => { visit += 1; refresh(); });
454
+ if (wanted(module)) {
455
+ start(module);
456
+ syncAreas();
457
+ }
458
+ },
459
+ setFlags(next) {
460
+ flags = { ...next };
461
+ refresh();
462
+ },
463
+ refresh,
464
+ active: () => [...running.keys()],
465
+ health,
466
+ openSettings,
467
+ dispose() {
468
+ stopRoutes?.();
469
+ stopRoutes = null;
470
+ for (const id of [...running.keys()])
471
+ stop(id);
472
+ for (const scope of areaScopes.values())
473
+ scope.dispose();
474
+ areaScopes.clear();
475
+ for (const shown of healthScopes.values())
476
+ shown.scope.dispose();
477
+ healthScopes.clear();
478
+ modules.clear();
479
+ },
480
+ };
481
+ }
482
+ /** Whether an area's switch is on in `flags` (a missing value counts as on). */
483
+ export const areaEnabled = (flags, area) => flags[areaFlag(area)] !== false;
484
+ //# sourceMappingURL=featureModules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureModules.js","sourceRoot":"","sources":["../../../runtime/src/featureModules.ts"],"names":[],"mappings":"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","sourcesContent":["// Feature modules: the code side of the feature table (featureTable.ts). An app's area plugins\n// (\"Navigation+\") are sets of small modules, one per feature; the registry starts a module only\n// while its flag is on, its area's switch is on and the page is on one of its surfaces, and\n// disposes everything it did when any of those stops being true. A hundred features then cost what\n// the ones on screen cost:\n//\n// const registry = createFeatureRegistry({ win, table, api, label, surfaces, message });\n// registry.define({ id: 'navigation.keyboardPlus', start(ctx) { ctx.onKey(...); } });\n// registry.setFlags(effectiveFlags(table, flags)); // from the app's feature flags\n//\n// A module's `start(ctx)` gets a context whose every helper is undone on stop: CSS, listeners,\n// nodes, DOM watching through the shared hub (one MutationObserver for every feature, domHub.ts),\n// palette commands under its area's name, its words, its storage and its settings. A module with a\n// `settings` schema gets a settings dialog drawn from the UI kit (settingsForm.ts); each area with\n// such a feature gets one \"settings\" palette command.\n//\n// Health: a module names the selectors it depends on (`probes`). After the page has settled, a\n// probe that matches nothing is a miss; three misses in a row (three visits) pause that one feature\n// for the session, with one toast and a note in the settings dialog. The site's markup changed; the\n// rest of the area keeps working. A signed hotfix may replace a probe's selector\n// (`selectors[\"<feature id>.<probe>\"]`) or switch a feature off (`flags[\"<feature id>\"] = false`).\n\nimport { domRoots, hasShadowHosts, isHeavyPath, observeSelector, watchDom, type DomWatch, type DomWatchHandle, type DomWindow } from './domHub.ts';\nimport { adoptStyles, type RootStyles } from './styles.ts';\nimport { HEALTH_COMMAND, areaFlag, healthKeywords, type AreaSpec, type FeatureSpec, type FeatureTable, type Flags } from './featureTable.ts';\nimport { formatMessage, type Params } from './i18n.ts';\nimport type { CommandDefinition } from './commands.ts';\nimport type { PluginI18n } from './pluginI18n.ts';\nimport type { Dispose, PluginScope, PluginStorage } from './pluginApi.ts';\nimport { buildSettingsForm, normalizeSettings, validateSchema, type SettingValues, type SettingsSchema } from './settingsForm.ts';\nimport { KIT_MESSAGES, type KitKey, type UiKit } from './ui.ts';\n\n/** Palette commands one area may register: its \"settings\" entry and four actions (the tab reports at most 48). */\nexport const AREA_COMMAND_BUDGET = 5;\n/** Misses in a row (separate visits) before a feature pauses itself. */\nexport const PROBE_STRIKES = 3;\n\n\n/**\n * A selector a feature depends on. `english`: it reads an English label, so it only counts on an\n * English page. `when`: it only counts while this selector matches (the part of the page it lives\n * in is there: a column the site drops in a narrow window is no verdict).\n */\nexport type Probe = string | { selector: string; english?: boolean; when?: string };\n\nexport type FeatureSettings = {\n /** The stored values, normalized by the schema. */\n get(): SettingValues;\n /** Saves (merged over the current values). False when storage refused it. */\n set(patch: SettingValues): boolean;\n /** Calls `callback(values)` after a save, until the feature stops. */\n onChange(callback: (values: SettingValues) => void): void;\n /** Opens this feature's settings dialog. */\n open(): void;\n};\n\nexport type FeatureContext<Api> = {\n /** The flag id and the feature's own name (`navigation.focusMode` -> `focusMode`). */\n readonly id: string;\n readonly name: string;\n readonly area: AreaSpec;\n /** The app's plugin API, unrestricted: a feature module is the app's own code. */\n readonly api: Api;\n /** The page's window (use it and its `document` instead of the globals: tests run without them). */\n readonly win: Window & typeof globalThis;\n /** This feature's stylesheet (one per `name`, replaced in place, cleared by an empty string; removed on stop). It also styles the site's configured open shadow roots (domHub `shadowHosts`). */\n css(css: string, name?: string): void;\n /** `callback` once per element matching `selector`, through the shared hub; paused on heavy pages unless the feature says `heavy`. */\n observe(selector: string, callback: (element: Element) => void): void;\n /** A raw hub subscription (domHub `watchDom`), disposed on stop. */\n watch(run: () => void, options?: DomWatch): DomWatchHandle;\n on(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n onKey(callback: (event: KeyboardEvent, item: Element | null) => void): void;\n onRouteChange(callback: (href: string, previous: string) => void): void;\n /** Tracks a node the feature inserted; removed on stop. */\n add<T extends Node>(node: T): T;\n /** Runs `fn` on stop. */\n defer(fn: Dispose): void;\n /** The UI kit; what the feature opened is closed on stop. */\n readonly ui: UiKit;\n /** A palette command under the area's name (counts towards `AREA_COMMAND_BUDGET`), removed on stop. */\n command(definition: CommandDefinition): void;\n /**\n * The feature's word `key`: `plugin.<area namespace>.<name>.<key>` in the app's catalog, or\n * `plugin.<words>.<key>` for a module that names its own namespace (`words`). (Not\n * named `t`: the i18n tools read `t('…')` as a whole catalog key.)\n */\n text(key: string, params?: Params): string;\n /** The feature's storage (its module's `storage` namespace). */\n readonly storage: PluginStorage;\n /** Its settings (a module with a `settings` schema; otherwise empty values). */\n readonly settings: FeatureSettings;\n /** The selector of probe `name` (a hotfix override wins). */\n selector(name: string): string;\n /** The surfaces the page is on right now. */\n surfaces(): readonly string[];\n};\n\nexport type FeatureModule<Api> = {\n /** The flag id; the table must list it with `backing: 'module'`. */\n id: string;\n /** Selectors it depends on, by name (read them back with `ctx.selector(name)`). */\n probes?: Readonly<Record<string, Probe>>;\n /**\n * Where its words are in the catalog. Default: `plugin.<area namespace>.<name>.<key>`. A feature\n * ported from a plugin names that plugin's namespace (`focus-mode`) and keeps its keys\n * (`plugin.focus-mode.<key>`, its label `plugin.focus-mode.name`): nothing is retranslated.\n */\n words?: string;\n /** Storage namespace (default `<area namespace>.<name>`; a ported plugin keeps its old one). */\n storage?: string;\n /** The key its settings are stored under (default `settings`). */\n settingsKey?: string;\n settings?: SettingsSchema;\n start(ctx: FeatureContext<Api>): void;\n};\n\n/** What the registry needs of the plugin API (the core API has all of it). */\nexport type RegistryApi = {\n scope(): PluginScope;\n injectCSS(id: string, css: string): void;\n clearCSS(id: string): void;\n storage(namespace: string): PluginStorage;\n onRouteChange(callback: (href: string, previous: string) => void): Dispose;\n ui: UiKit;\n i18n: PluginI18n;\n commands: { withOwner<T>(owner: string, fn: () => T): T };\n};\n\nexport type HotfixData = { selectors?: Readonly<Record<string, unknown>>; flags?: Readonly<Record<string, unknown>> };\n\nexport type FeatureHealth = { id: string; area: string; state: 'paused' | 'needs-english'; probes: string[] };\n\nexport type FeatureRegistryOptions<Api extends RegistryApi> = {\n win: Window & typeof globalThis;\n table: FeatureTable;\n api: Api;\n /** Console prefix (the app's name). */\n label: string;\n /** The surfaces the page is on (`['timeline', 'home']`); the app's classifier. */\n surfaces(): readonly string[];\n /** The app catalog's message for `key` in the active language (the registry's words are the kit's: `kit.feature.*`, `kit.save`). */\n message?(key: string): string | undefined;\n locale?(): string;\n /** The signed hotfix data, when the app has any (selector overrides and kill flags). */\n hotfix?(): HotfixData | null | undefined;\n /** The page has rendered its content (the site's main column is there); default: the body has children. */\n settled?(): boolean;\n /** The page's language is English (probes marked `english` only count then); default: `<html lang>` starts with `en`. */\n english?(): boolean;\n /** ms after the page settled before probes are judged (default 3000) and between settle checks (default 500). */\n settleMs?: number;\n pollMs?: number;\n timers?: { setTimeout(fn: () => void, ms: number): unknown; clearTimeout(id: unknown): void };\n};\n\nexport type FeatureRegistry<Api> = {\n define(module: FeatureModule<Api>): void;\n /** The effective flags (featureTable `effectiveFlags`): starts and stops modules to match. */\n setFlags(flags: Readonly<Flags>): void;\n /** Re-checks surfaces (the registry also does it on every route change). */\n refresh(): void;\n /** The ids of the modules running right now. */\n active(): string[];\n /** Paused features and features waiting for an English page. */\n health(): FeatureHealth[];\n /** Opens the settings dialog of an area (or of one feature). False when nothing in it has settings right now. */\n openSettings(area: string, feature?: string): boolean;\n /** Stops everything (the runtime is going away; tests). */\n dispose(): void;\n};\n\ntype Running<Api> = {\n module: FeatureModule<Api>;\n spec: FeatureSpec;\n area: AreaSpec;\n scope: PluginScope;\n commands: number;\n listeners: Set<(values: SettingValues) => void>;\n settings: FeatureSettings;\n visit: number;\n timer: unknown;\n};\n\nconst featureName = (id: string) => id.slice(id.indexOf('.') + 1);\n\nexport function createFeatureRegistry<Api extends RegistryApi>(options: FeatureRegistryOptions<Api>): FeatureRegistry<Api> {\n const { win, table, api, label } = options;\n const doc = win.document;\n const timers = options.timers ?? { setTimeout: (fn: () => void, ms: number) => win.setTimeout(fn, ms), clearTimeout: (id: unknown) => win.clearTimeout(id as number) };\n const settleMs = options.settleMs ?? 3000;\n const pollMs = options.pollMs ?? 500;\n const specs = new Map(table.features.map(feature => [feature.id, feature]));\n const areas = new Map(table.areas.map(area => [area.id, area]));\n const modules = new Map<string, FeatureModule<Api>>();\n const running = new Map<string, Running<Api>>();\n const areaScopes = new Map<string, PluginScope>();\n const healthScopes = new Map<string, { scope: PluginScope; ids: string }>();\n const strikes = new Map<string, number>();\n const paused = new Map<string, string[]>();\n const waiting = new Map<string, string[]>();\n let flags: Readonly<Flags> = {};\n let stopRoutes: Dispose | null = null;\n let visit = 0;\n\n // The registry's own words are the kit's (`kit.feature.*`, `kit.save`): English unless the app delivers them.\n const text = (key: KitKey, params: Params = {}) =>\n formatMessage(options.message?.(key) ?? KIT_MESSAGES[key], params, options.locale?.() ?? 'en');\n const hotfix = (): HotfixData => { try { return options.hotfix?.() ?? {}; } catch { return {}; } };\n const english = () => options.english?.() ?? /^en\\b/i.test(doc.documentElement?.getAttribute?.('lang') ?? 'en');\n const settled = () => options.settled?.() ?? !!doc.body?.firstElementChild;\n /** A selector matches in the page or in one of its configured open shadow roots. */\n const inPage = (selector: string) => domRoots(doc.defaultView ?? { document: doc }).some(root => !!root.querySelector(selector));\n const words = (area: AreaSpec) => api.i18n.namespace(area.namespace);\n /** A feature's word `key`: under its own namespace when it names one (`words`), else under its area's. */\n const wordOf = (module: FeatureModule<Api>, area: AreaSpec, key: string, params?: Params) =>\n (module.words ? api.i18n.namespace(module.words).t(key, params) : words(area).t(`${featureName(module.id)}.${key}`, params));\n /** A feature's label in the page, when the page has it (`plugin.*` words only reach a site tab). */\n const featureLabel = (spec: FeatureSpec, area: AreaSpec) => {\n const legacy = modules.get(spec.id)?.words;\n if (legacy) { const own = api.i18n.namespace(legacy); return own.has('name') ? own.t('name') : null; }\n const i18n = words(area);\n const key = `feature.${featureName(spec.id)}.label`;\n return i18n.has(key) ? i18n.t(key) : null;\n };\n\n const selectorOf = (module: FeatureModule<Api>, name: string) => {\n const override = hotfix().selectors?.[`${module.id}.${name}`];\n if (typeof override === 'string' && override.trim()) return override;\n const probe = module.probes?.[name];\n if (probe === undefined) throw new Error(`${module.id}: no probe named ${JSON.stringify(name)}`);\n return typeof probe === 'string' ? probe : probe.selector;\n };\n\n function wanted(module: FeatureModule<Api>): boolean {\n const spec = specs.get(module.id)!;\n if (flags[module.id] !== true || paused.has(module.id) || hotfix().flags?.[module.id] === false) return false;\n if (!spec.heavy && isHeavyPath(win.location.pathname ?? '')) return false;\n if (!spec.surfaces?.length) return true;\n const on = options.surfaces();\n return spec.surfaces.some(surface => on.includes(surface));\n }\n\n function settingsOf(module: FeatureModule<Api>, area: AreaSpec, listeners: Set<(values: SettingValues) => void>): FeatureSettings {\n const schema = module.settings ?? [];\n const store = () => api.storage(module.storage ?? `${area.namespace}.${featureName(module.id)}`);\n const key = module.settingsKey ?? 'settings';\n const get = () => normalizeSettings(schema, store().get<unknown>(key, null));\n return {\n get,\n set(patch) {\n const next = normalizeSettings(schema, { ...get(), ...patch });\n const saved = store().set(key, next);\n for (const listener of [...listeners]) {\n try { listener(next); } catch (error) { console.error(`[${label}] ${module.id} settings listener failed`, error); }\n }\n return saved;\n },\n onChange(callback) { listeners.add(callback); },\n open() { openSettings(area.id, module.id); },\n };\n }\n\n function start(module: FeatureModule<Api>) {\n const spec = specs.get(module.id)!;\n const area = areas.get(spec.area!)!;\n const scope = api.commands.withOwner(area.owner, () => api.scope());\n const listeners = new Set<(values: SettingValues) => void>();\n const entry: Running<Api> = { module, spec, area, scope, commands: 0, listeners, settings: settingsOf(module, area, listeners), visit: -1, timer: null };\n const name = featureName(module.id);\n const domWin = win as unknown as DomWindow;\n const styles = new Set<string>();\n // The same sheets, adopted by each configured open shadow root of the page (a site part rendered\n // inside one, e.g. X's chat embed); roots that appear later get them on the next hub frame.\n const rootCss = new Map<string, string>();\n const rootSheets = new Map<Node, Map<string, { sheet: RootStyles; css: string }>>();\n let rootWatch: DomWatchHandle | null = null;\n const syncRoots = () => {\n const roots = domRoots(domWin).slice(1);\n for (const [root, sheets] of rootSheets) {\n if (roots.includes(root as ShadowRoot)) continue;\n for (const item of sheets.values()) item.sheet.remove();\n rootSheets.delete(root);\n }\n for (const root of roots) {\n let sheets = rootSheets.get(root);\n if (!sheets) { sheets = new Map(); rootSheets.set(root, sheets); }\n for (const [styleId, item] of sheets) if (!rootCss.has(styleId)) { item.sheet.remove(); sheets.delete(styleId); }\n for (const [styleId, css] of rootCss) {\n const item = sheets.get(styleId);\n if (!item) sheets.set(styleId, { sheet: adoptStyles(root as ShadowRoot, css), css });\n else if (item.css !== css) { item.sheet.update(css); item.css = css; }\n }\n }\n };\n const ctx: FeatureContext<Api> = {\n id: module.id,\n name,\n area,\n api,\n win,\n css(css, part = '') {\n const styleId = `wbf-${module.id}${part ? `-${part}` : ''}`;\n if (!styles.has(styleId)) { styles.add(styleId); scope.defer(() => api.clearCSS(styleId)); }\n if (css) api.injectCSS(styleId, css); else api.clearCSS(styleId);\n if (css) rootCss.set(styleId, css); else rootCss.delete(styleId);\n if (!rootWatch && css && hasShadowHosts()) {\n rootWatch = watchDom(domWin, syncRoots, { offOnHeavy: !spec.heavy });\n scope.defer(() => {\n rootWatch?.dispose(); rootWatch = null;\n rootCss.clear();\n for (const sheets of rootSheets.values()) for (const item of sheets.values()) item.sheet.remove();\n rootSheets.clear();\n });\n }\n if (rootWatch) syncRoots();\n },\n observe(selector, callback) {\n scope.defer(observeSelector(domWin, selector, callback, { offOnHeavy: !spec.heavy, report: error => console.error(`[${label}] ${module.id} failed`, error) }));\n },\n watch(run, watchOptions = {}) {\n const handle = watchDom(domWin, run, { offOnHeavy: !spec.heavy, ...watchOptions });\n scope.defer(() => handle.dispose());\n return handle;\n },\n on: (target, type, listener, listenerOptions) => scope.on(target, type, listener, listenerOptions),\n onKey: callback => scope.onKey(callback),\n onRouteChange: callback => scope.onRouteChange(callback),\n add: node => scope.add(node),\n defer: fn => scope.defer(fn),\n get ui() { return scope.ui; },\n command(definition) {\n const reserved = table.features.some(feature => feature.area === area.id && feature.settings) ? 1 : 0;\n const used = [...running.values()].filter(other => other.area.id === area.id).reduce((sum, other) => sum + other.commands, 0);\n if (used + reserved >= AREA_COMMAND_BUDGET) throw new Error(`${area.name}: at most ${AREA_COMMAND_BUDGET} palette commands per area`);\n scope.commands.register(definition);\n entry.commands += 1;\n },\n text: (key, params) => wordOf(module, area, key, params),\n get storage() { return api.storage(module.storage ?? `${area.namespace}.${name}`); },\n settings: entry.settings,\n selector: probe => selectorOf(module, probe),\n surfaces: () => options.surfaces(),\n };\n running.set(module.id, entry);\n try {\n module.start(ctx);\n } catch (error) {\n console.error(`[${label}] ${module.id} failed`, error);\n stop(module.id);\n return;\n }\n scheduleProbes(entry);\n }\n\n function stop(id: string) {\n const entry = running.get(id);\n if (!entry) return;\n running.delete(id);\n if (entry.timer !== null) timers.clearTimeout(entry.timer);\n entry.listeners.clear();\n entry.scope.dispose();\n }\n\n // ---- Health ----------------------------------------------------------------------------------\n\n function scheduleProbes(entry: Running<Api>) {\n if (!entry.module.probes || !Object.keys(entry.module.probes).length || entry.visit === visit) return;\n entry.visit = visit;\n if (entry.timer !== null) timers.clearTimeout(entry.timer);\n const mine = visit;\n let tries = 0;\n const waitForSettle = () => {\n entry.timer = null;\n if (running.get(entry.module.id) !== entry || mine !== visit) return;\n if (!settled()) {\n tries += 1;\n // A page that never settles (an error page, a sign-in wall) is no verdict.\n if (tries <= 20) entry.timer = timers.setTimeout(waitForSettle, pollMs);\n return;\n }\n entry.timer = timers.setTimeout(judge, settleMs);\n };\n const judge = () => {\n entry.timer = null;\n if (running.get(entry.module.id) !== entry || mine !== visit) return;\n const id = entry.module.id;\n const missing: string[] = [];\n const needEnglish: string[] = [];\n const inEnglish = english();\n for (const [name, probe] of Object.entries(entry.module.probes ?? {})) {\n if (typeof probe !== 'string' && probe.english && !inEnglish) { needEnglish.push(name); continue; }\n if (typeof probe !== 'string' && probe.when) {\n let there = false;\n try { there = inPage(probe.when); } catch { there = false; }\n if (!there) continue;\n }\n let found = false;\n try { found = inPage(selectorOf(entry.module, name)); } catch { found = false; }\n if (!found) missing.push(name);\n }\n if (needEnglish.length) waiting.set(id, needEnglish); else waiting.delete(id);\n if (!missing.length) { strikes.delete(id); return; }\n const count = (strikes.get(id) ?? 0) + 1;\n strikes.set(id, count);\n if (count < PROBE_STRIKES) return;\n paused.set(id, missing);\n stop(id);\n syncAreas();\n console.warn(`[${label}] ${id} paused: nothing matches ${missing.join(', ')}`);\n const feature = featureLabel(entry.spec, entry.area);\n try {\n api.ui.toast(feature ? text('kit.feature.paused', { feature, area: entry.area.name }) : text('kit.feature.pausedOne', { area: entry.area.name }), { tone: 'warning', duration: 8000 });\n } catch { /* a page without a body yet: the note in the settings dialog remains */ }\n };\n entry.timer = timers.setTimeout(waitForSettle, pollMs);\n }\n\n // ---- Settings dialog and the area's command --------------------------------------------------\n\n function openSettings(areaId: string, only?: string): boolean {\n const area = areas.get(areaId);\n if (!area) return false;\n const entries = [...running.values()].filter(entry => entry.area.id === areaId && entry.module.settings?.length && (!only || entry.module.id === only));\n const notes = health().filter(note => note.area === areaId);\n if (!entries.length && !notes.length) return false;\n const ui = api.ui;\n const h = ui.h;\n const forms = entries.map(entry => {\n const name = featureName(entry.module.id);\n return { entry, title: featureLabel(entry.spec, area) ?? name, form: buildSettingsForm(h, entry.module.settings!, entry.settings.get(), key => wordOf(entry.module, area, key)) };\n });\n const single = forms.length === 1 && !notes.length ? forms[0]! : null;\n ui.dialog({\n title: text('kit.feature.settings', { name: single ? single.title : area.name }),\n content: body => {\n forms.forEach((item, index) => {\n if (index > 0) body.append(h('div', { class: 'wb-divider' }));\n if (!single) body.append(h('p', { class: 'wb-label' }, item.title));\n body.append(...item.form.nodes);\n });\n for (const note of notes) {\n const spec = specs.get(note.id)!;\n const feature = featureLabel(spec, area) ?? featureName(note.id);\n body.append(h('p', { class: 'wb-hint' }, note.state === 'paused' ? text('kit.feature.paused', { feature, area: area.name }) : text('kit.feature.needsEnglish', { feature })));\n }\n },\n actions: forms.length ? [\n { label: text('kit.cancel') },\n {\n label: text('kit.save'), tone: 'primary', default: true,\n onClick: handle => {\n const failed = forms.filter(item => !item.entry.settings.set(item.form.read()));\n if (failed.length) { handle.setError(text('kit.failed')); return false; }\n return undefined;\n },\n },\n ] : undefined,\n });\n return true;\n }\n\n /** Each area with a running feature that has settings gets its one \"settings\" palette command. */\n function syncAreas() {\n for (const area of table.areas) {\n const needs = [...running.values()].some(entry => entry.area.id === area.id && entry.module.settings?.length);\n const scope = areaScopes.get(area.id);\n if (needs && !scope) {\n const created = api.commands.withOwner(area.owner, () => api.scope());\n areaScopes.set(area.id, created);\n try {\n created.commands.register({ id: 'settings', title: text('kit.feature.settings', { name: area.name }), keywords: `settings options configure ${area.name}`, run: () => { openSettings(area.id); } });\n } catch (error) { console.error(`[${label}] ${area.name} settings command failed`, error); }\n } else if (!needs && scope) {\n scope.dispose();\n areaScopes.delete(area.id);\n }\n // A paused feature that would run (its flag and area are on) is named in the palette: the\n // entry opens the notes, and the panel reads it for the feature's row (featureTable `pausedFeatures`).\n const ids = [...paused.keys()].filter(id => specs.get(id)!.area === area.id && flags[id] === true).join(' ');\n const shown = healthScopes.get(area.id);\n if (shown && shown.ids !== ids) { shown.scope.dispose(); healthScopes.delete(area.id); }\n if (ids && !healthScopes.has(area.id)) {\n const created = api.commands.withOwner(area.owner, () => api.scope());\n healthScopes.set(area.id, { scope: created, ids });\n try {\n created.commands.register({ id: HEALTH_COMMAND, title: text('kit.feature.pausedList', { area: area.name }), keywords: healthKeywords(ids.split(' ')), run: () => { openSettings(area.id); } });\n } catch (error) { console.error(`[${label}] ${area.name} health command failed`, error); }\n }\n }\n }\n\n function health(): FeatureHealth[] {\n const out: FeatureHealth[] = [];\n for (const [id, probes] of paused) out.push({ id, area: specs.get(id)!.area!, state: 'paused', probes });\n for (const [id, probes] of waiting) if (!paused.has(id)) out.push({ id, area: specs.get(id)!.area!, state: 'needs-english', probes });\n return out;\n }\n\n function refresh() {\n for (const module of modules.values()) {\n const on = running.has(module.id);\n const want = wanted(module);\n if (want && !on) start(module);\n else if (!want && on) stop(module.id);\n else if (want && on) scheduleProbes(running.get(module.id)!);\n }\n syncAreas();\n }\n\n return {\n define(module) {\n const spec = specs.get(module.id);\n if (!spec || spec.backing !== 'module' || spec.area === null || !areas.has(spec.area)) throw new Error(`${label}: ${module.id} is not a feature module in the table`);\n if (modules.has(module.id)) throw new Error(`${label}: ${module.id} is defined twice`);\n const problems = validateSchema(module.settings ?? []);\n if (problems.length) throw new Error(`${label}: ${module.id} settings: ${problems.join('; ')}`);\n if (!!module.settings?.length !== !!spec.settings) throw new Error(`${label}: ${module.id}: the table's \"settings\" and the module's schema disagree`);\n modules.set(module.id, module);\n stopRoutes ??= api.onRouteChange(() => { visit += 1; refresh(); });\n if (wanted(module)) { start(module); syncAreas(); }\n },\n setFlags(next) {\n flags = { ...next };\n refresh();\n },\n refresh,\n active: () => [...running.keys()],\n health,\n openSettings,\n dispose() {\n stopRoutes?.();\n stopRoutes = null;\n for (const id of [...running.keys()]) stop(id);\n for (const scope of areaScopes.values()) scope.dispose();\n areaScopes.clear();\n for (const shown of healthScopes.values()) shown.scope.dispose();\n healthScopes.clear();\n modules.clear();\n },\n };\n}\n\n/** Whether an area's switch is on in `flags` (a missing value counts as on). */\nexport const areaEnabled = (flags: Readonly<Flags>, area: string) => flags[areaFlag(area)] !== false;\n"]}