react-cheminfo 0.64.1 → 0.66.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 (827) hide show
  1. package/README.md +293 -6
  2. package/lib/card/core/cardAddress.d.ts +70 -0
  3. package/lib/card/core/cardAddress.d.ts.map +1 -0
  4. package/lib/card/core/cardAddress.js +59 -0
  5. package/lib/card/core/cardAddress.js.map +1 -0
  6. package/lib/card/core/cardPageUrl.d.ts +49 -0
  7. package/lib/card/core/cardPageUrl.d.ts.map +1 -0
  8. package/lib/card/core/cardPageUrl.js +59 -0
  9. package/lib/card/core/cardPageUrl.js.map +1 -0
  10. package/lib/card/core/index.d.ts +7 -0
  11. package/lib/card/core/index.d.ts.map +1 -0
  12. package/lib/card/core/index.js +4 -0
  13. package/lib/card/core/index.js.map +1 -0
  14. package/lib/card/core/panelRoom.d.ts +40 -0
  15. package/lib/card/core/panelRoom.d.ts.map +1 -0
  16. package/lib/card/core/panelRoom.js +40 -0
  17. package/lib/card/core/panelRoom.js.map +1 -0
  18. package/lib/card/ui/CardDetailsButton.d.ts +38 -0
  19. package/lib/card/ui/CardDetailsButton.d.ts.map +1 -0
  20. package/lib/card/ui/CardDetailsButton.js +50 -0
  21. package/lib/card/ui/CardDetailsButton.js.map +1 -0
  22. package/lib/card/ui/CardFigure.d.ts +51 -0
  23. package/lib/card/ui/CardFigure.d.ts.map +1 -0
  24. package/lib/card/ui/CardFigure.js +27 -0
  25. package/lib/card/ui/CardFigure.js.map +1 -0
  26. package/lib/card/ui/CardFrame.d.ts +30 -0
  27. package/lib/card/ui/CardFrame.d.ts.map +1 -0
  28. package/lib/card/ui/CardFrame.js +20 -0
  29. package/lib/card/ui/CardFrame.js.map +1 -0
  30. package/lib/card/ui/CopyTableButton.d.ts +37 -0
  31. package/lib/card/ui/CopyTableButton.d.ts.map +1 -0
  32. package/lib/card/ui/CopyTableButton.js +19 -0
  33. package/lib/card/ui/CopyTableButton.js.map +1 -0
  34. package/lib/card/ui/cardTooltip.d.ts +14 -0
  35. package/lib/card/ui/cardTooltip.d.ts.map +1 -0
  36. package/lib/card/ui/cardTooltip.js +15 -0
  37. package/lib/card/ui/cardTooltip.js.map +1 -0
  38. package/lib/card/ui/embed.d.ts +15 -0
  39. package/lib/card/ui/embed.d.ts.map +1 -0
  40. package/lib/card/ui/embed.js +24 -0
  41. package/lib/card/ui/embed.js.map +1 -0
  42. package/lib/card/ui/fitCardToFrame.d.ts +31 -0
  43. package/lib/card/ui/fitCardToFrame.d.ts.map +1 -0
  44. package/lib/card/ui/fitCardToFrame.js +66 -0
  45. package/lib/card/ui/fitCardToFrame.js.map +1 -0
  46. package/lib/card/ui/holdRoomForPanels.d.ts +16 -0
  47. package/lib/card/ui/holdRoomForPanels.d.ts.map +1 -0
  48. package/lib/card/ui/holdRoomForPanels.js +76 -0
  49. package/lib/card/ui/holdRoomForPanels.js.map +1 -0
  50. package/lib/card/ui/index.d.ts +11 -0
  51. package/lib/card/ui/index.d.ts.map +1 -0
  52. package/lib/card/ui/index.js +7 -0
  53. package/lib/card/ui/index.js.map +1 -0
  54. package/lib/card/ui/openPanels.d.ts +25 -0
  55. package/lib/card/ui/openPanels.d.ts.map +1 -0
  56. package/lib/card/ui/openPanels.js +85 -0
  57. package/lib/card/ui/openPanels.js.map +1 -0
  58. package/lib/card.d.ts +13 -0
  59. package/lib/card.d.ts.map +1 -0
  60. package/lib/card.js +13 -0
  61. package/lib/card.js.map +1 -0
  62. package/lib/conformers.d.ts +1 -0
  63. package/lib/conformers.d.ts.map +1 -1
  64. package/lib/conformers.js +1 -0
  65. package/lib/conformers.js.map +1 -1
  66. package/lib/core.d.ts +4 -0
  67. package/lib/core.d.ts.map +1 -1
  68. package/lib/core.js +5 -0
  69. package/lib/core.js.map +1 -1
  70. package/lib/fetch/core/apiError.d.ts +56 -0
  71. package/lib/fetch/core/apiError.d.ts.map +1 -0
  72. package/lib/fetch/core/apiError.js +43 -0
  73. package/lib/fetch/core/apiError.js.map +1 -0
  74. package/lib/fetch/core/fetchJson.d.ts +47 -0
  75. package/lib/fetch/core/fetchJson.d.ts.map +1 -0
  76. package/lib/fetch/core/fetchJson.js +109 -0
  77. package/lib/fetch/core/fetchJson.js.map +1 -0
  78. package/lib/fetch/core/index.d.ts +5 -0
  79. package/lib/fetch/core/index.d.ts.map +1 -0
  80. package/lib/fetch/core/index.js +3 -0
  81. package/lib/fetch/core/index.js.map +1 -0
  82. package/lib/formula/core/formulaText.d.ts +46 -0
  83. package/lib/formula/core/formulaText.d.ts.map +1 -0
  84. package/lib/formula/core/formulaText.js +74 -0
  85. package/lib/formula/core/formulaText.js.map +1 -0
  86. package/lib/formula/core/index.d.ts +6 -0
  87. package/lib/formula/core/index.d.ts.map +1 -0
  88. package/lib/formula/core/index.js +4 -0
  89. package/lib/formula/core/index.js.map +1 -0
  90. package/lib/formula/core/normalizeFormula.d.ts +22 -0
  91. package/lib/formula/core/normalizeFormula.d.ts.map +1 -0
  92. package/lib/formula/core/normalizeFormula.js +46 -0
  93. package/lib/formula/core/normalizeFormula.js.map +1 -0
  94. package/lib/formula/core/readFormula.d.ts +73 -0
  95. package/lib/formula/core/readFormula.d.ts.map +1 -0
  96. package/lib/formula/core/readFormula.js +132 -0
  97. package/lib/formula/core/readFormula.js.map +1 -0
  98. package/lib/formula/ui/CopyableFormula.d.ts +31 -0
  99. package/lib/formula/ui/CopyableFormula.d.ts.map +1 -0
  100. package/lib/formula/ui/CopyableFormula.js +19 -0
  101. package/lib/formula/ui/CopyableFormula.js.map +1 -0
  102. package/lib/formula/ui/FormulaInput.d.ts +29 -0
  103. package/lib/formula/ui/FormulaInput.d.ts.map +1 -0
  104. package/lib/formula/ui/FormulaInput.js +16 -0
  105. package/lib/formula/ui/FormulaInput.js.map +1 -0
  106. package/lib/formula/ui/QuestionFormula.d.ts +14 -0
  107. package/lib/formula/ui/QuestionFormula.d.ts.map +1 -0
  108. package/lib/formula/ui/QuestionFormula.js +13 -0
  109. package/lib/formula/ui/QuestionFormula.js.map +1 -0
  110. package/lib/formula/ui/index.d.ts +7 -0
  111. package/lib/formula/ui/index.d.ts.map +1 -0
  112. package/lib/formula/ui/index.js +4 -0
  113. package/lib/formula/ui/index.js.map +1 -0
  114. package/lib/formula.d.ts +11 -0
  115. package/lib/formula.d.ts.map +1 -0
  116. package/lib/formula.js +11 -0
  117. package/lib/formula.js.map +1 -0
  118. package/lib/hooks/ui/index.d.ts +1 -0
  119. package/lib/hooks/ui/index.d.ts.map +1 -1
  120. package/lib/hooks/ui/index.js.map +1 -1
  121. package/lib/hooks/ui/keyTargets.d.ts +4 -2
  122. package/lib/hooks/ui/keyTargets.d.ts.map +1 -1
  123. package/lib/hooks/ui/keyTargets.js +5 -3
  124. package/lib/hooks/ui/keyTargets.js.map +1 -1
  125. package/lib/hooks/ui/useAsync.d.ts +20 -5
  126. package/lib/hooks/ui/useAsync.d.ts.map +1 -1
  127. package/lib/hooks/ui/useAsync.js +29 -14
  128. package/lib/hooks/ui/useAsync.js.map +1 -1
  129. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  130. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  131. package/lib/ir/core/analysisSpectra.d.ts +23 -6
  132. package/lib/ir/core/analysisSpectra.d.ts.map +1 -1
  133. package/lib/ir/core/analysisSpectra.js.map +1 -1
  134. package/lib/ir/core/bandLabelPlan.d.ts.map +1 -1
  135. package/lib/ir/core/bandLabelPlan.js +11 -6
  136. package/lib/ir/core/bandLabelPlan.js.map +1 -1
  137. package/lib/ir/core/index.d.ts +13 -9
  138. package/lib/ir/core/index.d.ts.map +1 -1
  139. package/lib/ir/core/index.js +9 -6
  140. package/lib/ir/core/index.js.map +1 -1
  141. package/lib/ir/core/irBand.d.ts +45 -14
  142. package/lib/ir/core/irBand.d.ts.map +1 -1
  143. package/lib/ir/core/irBand.js +28 -6
  144. package/lib/ir/core/irBand.js.map +1 -1
  145. package/lib/ir/core/irCommands.d.ts +11 -0
  146. package/lib/ir/core/irCommands.d.ts.map +1 -1
  147. package/lib/ir/core/irCommands.js +11 -1
  148. package/lib/ir/core/irCommands.js.map +1 -1
  149. package/lib/ir/core/irDomain.d.ts +4 -3
  150. package/lib/ir/core/irDomain.d.ts.map +1 -1
  151. package/lib/ir/core/irDomain.js +10 -7
  152. package/lib/ir/core/irDomain.js.map +1 -1
  153. package/lib/ir/core/irFormat.d.ts +14 -2
  154. package/lib/ir/core/irFormat.d.ts.map +1 -1
  155. package/lib/ir/core/irFormat.js +33 -4
  156. package/lib/ir/core/irFormat.js.map +1 -1
  157. package/lib/ir/core/irMode.d.ts +35 -8
  158. package/lib/ir/core/irMode.d.ts.map +1 -1
  159. package/lib/ir/core/irMode.js +38 -10
  160. package/lib/ir/core/irMode.js.map +1 -1
  161. package/lib/ir/core/irReducer.d.ts +0 -28
  162. package/lib/ir/core/irReducer.d.ts.map +1 -1
  163. package/lib/ir/core/irReducer.js +1 -24
  164. package/lib/ir/core/irReducer.js.map +1 -1
  165. package/lib/ir/core/irSpectrum.d.ts +52 -26
  166. package/lib/ir/core/irSpectrum.d.ts.map +1 -1
  167. package/lib/ir/core/irSpectrum.js +21 -15
  168. package/lib/ir/core/irSpectrum.js.map +1 -1
  169. package/lib/ir/core/irState.d.ts +40 -2
  170. package/lib/ir/core/irState.d.ts.map +1 -1
  171. package/lib/ir/core/irState.js +38 -1
  172. package/lib/ir/core/irState.js.map +1 -1
  173. package/lib/ir/core/irTechnique.d.ts +94 -0
  174. package/lib/ir/core/irTechnique.d.ts.map +1 -0
  175. package/lib/ir/core/irTechnique.js +87 -0
  176. package/lib/ir/core/irTechnique.js.map +1 -0
  177. package/lib/ir/core/irTechniqueCommands.d.ts +26 -0
  178. package/lib/ir/core/irTechniqueCommands.d.ts.map +1 -0
  179. package/lib/ir/core/irTechniqueCommands.js +68 -0
  180. package/lib/ir/core/irTechniqueCommands.js.map +1 -0
  181. package/lib/ir/core/pickBands.d.ts +6 -5
  182. package/lib/ir/core/pickBands.d.ts.map +1 -1
  183. package/lib/ir/core/pickBands.js +49 -26
  184. package/lib/ir/core/pickBands.js.map +1 -1
  185. package/lib/ir/core/ramanBands.d.ts +30 -0
  186. package/lib/ir/core/ramanBands.d.ts.map +1 -0
  187. package/lib/ir/core/ramanBands.js +83 -0
  188. package/lib/ir/core/ramanBands.js.map +1 -0
  189. package/lib/ir/core/spectrumJcamp.d.ts +10 -5
  190. package/lib/ir/core/spectrumJcamp.d.ts.map +1 -1
  191. package/lib/ir/core/spectrumJcamp.js +63 -15
  192. package/lib/ir/core/spectrumJcamp.js.map +1 -1
  193. package/lib/ir/core/toIrSpectrum.d.ts.map +1 -1
  194. package/lib/ir/core/toIrSpectrum.js +17 -2
  195. package/lib/ir/core/toIrSpectrum.js.map +1 -1
  196. package/lib/ir/ui/BandRow.d.ts +30 -0
  197. package/lib/ir/ui/BandRow.d.ts.map +1 -0
  198. package/lib/ir/ui/BandRow.js +42 -0
  199. package/lib/ir/ui/BandRow.js.map +1 -0
  200. package/lib/ir/ui/BandsPanel.d.ts +4 -0
  201. package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
  202. package/lib/ir/ui/BandsPanel.js +14 -59
  203. package/lib/ir/ui/BandsPanel.js.map +1 -1
  204. package/lib/ir/ui/IrAboutDialog.d.ts +7 -0
  205. package/lib/ir/ui/IrAboutDialog.d.ts.map +1 -1
  206. package/lib/ir/ui/IrAboutDialog.js +16 -3
  207. package/lib/ir/ui/IrAboutDialog.js.map +1 -1
  208. package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
  209. package/lib/ir/ui/IrCanvas.js +2 -2
  210. package/lib/ir/ui/IrCanvas.js.map +1 -1
  211. package/lib/ir/ui/IrChart.d.ts +2 -1
  212. package/lib/ir/ui/IrChart.d.ts.map +1 -1
  213. package/lib/ir/ui/IrChart.js +18 -21
  214. package/lib/ir/ui/IrChart.js.map +1 -1
  215. package/lib/ir/ui/IrCommandProvider.d.ts +7 -0
  216. package/lib/ir/ui/IrCommandProvider.d.ts.map +1 -1
  217. package/lib/ir/ui/IrCommandProvider.js +2 -2
  218. package/lib/ir/ui/IrCommandProvider.js.map +1 -1
  219. package/lib/ir/ui/IrCommandTooltip.d.ts +7 -0
  220. package/lib/ir/ui/IrCommandTooltip.d.ts.map +1 -1
  221. package/lib/ir/ui/IrCommandTooltip.js +3 -2
  222. package/lib/ir/ui/IrCommandTooltip.js.map +1 -1
  223. package/lib/ir/ui/IrDocumentationDialog.d.ts +8 -1
  224. package/lib/ir/ui/IrDocumentationDialog.d.ts.map +1 -1
  225. package/lib/ir/ui/IrDocumentationDialog.js +30 -7
  226. package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
  227. package/lib/ir/ui/IrEditor.d.ts +3 -1
  228. package/lib/ir/ui/IrEditor.d.ts.map +1 -1
  229. package/lib/ir/ui/IrEditor.js +3 -20
  230. package/lib/ir/ui/IrEditor.js.map +1 -1
  231. package/lib/ir/ui/IrHeader.d.ts.map +1 -1
  232. package/lib/ir/ui/IrHeader.js +5 -1
  233. package/lib/ir/ui/IrHeader.js.map +1 -1
  234. package/lib/ir/ui/IrLogo.d.ts +11 -3
  235. package/lib/ir/ui/IrLogo.d.ts.map +1 -1
  236. package/lib/ir/ui/IrLogo.js +14 -5
  237. package/lib/ir/ui/IrLogo.js.map +1 -1
  238. package/lib/ir/ui/IrShell.d.ts.map +1 -1
  239. package/lib/ir/ui/IrShell.js +23 -56
  240. package/lib/ir/ui/IrShell.js.map +1 -1
  241. package/lib/ir/ui/IrStatusBar.d.ts +3 -2
  242. package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
  243. package/lib/ir/ui/IrStatusBar.js +14 -9
  244. package/lib/ir/ui/IrStatusBar.js.map +1 -1
  245. package/lib/ir/ui/IrToolbar.d.ts +3 -0
  246. package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
  247. package/lib/ir/ui/IrToolbar.js +10 -3
  248. package/lib/ir/ui/IrToolbar.js.map +1 -1
  249. package/lib/ir/ui/IrTraces.d.ts +4 -1
  250. package/lib/ir/ui/IrTraces.d.ts.map +1 -1
  251. package/lib/ir/ui/IrTraces.js +2 -0
  252. package/lib/ir/ui/IrTraces.js.map +1 -1
  253. package/lib/ir/ui/RamanEditor.d.ts +46 -0
  254. package/lib/ir/ui/RamanEditor.d.ts.map +1 -0
  255. package/lib/ir/ui/RamanEditor.js +17 -0
  256. package/lib/ir/ui/RamanEditor.js.map +1 -0
  257. package/lib/ir/ui/SpectraPanel.d.ts.map +1 -1
  258. package/lib/ir/ui/SpectraPanel.js +2 -2
  259. package/lib/ir/ui/SpectraPanel.js.map +1 -1
  260. package/lib/ir/ui/SpectrumRow.d.ts +7 -0
  261. package/lib/ir/ui/SpectrumRow.d.ts.map +1 -1
  262. package/lib/ir/ui/SpectrumRow.js +4 -5
  263. package/lib/ir/ui/SpectrumRow.js.map +1 -1
  264. package/lib/ir/ui/VibrationalEditor.d.ts +48 -0
  265. package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -0
  266. package/lib/ir/ui/VibrationalEditor.js +31 -0
  267. package/lib/ir/ui/VibrationalEditor.js.map +1 -0
  268. package/lib/ir/ui/bandsTsv.d.ts +19 -0
  269. package/lib/ir/ui/bandsTsv.d.ts.map +1 -0
  270. package/lib/ir/ui/bandsTsv.js +38 -0
  271. package/lib/ir/ui/bandsTsv.js.map +1 -0
  272. package/lib/ir/ui/irChartProps.d.ts +14 -4
  273. package/lib/ir/ui/irChartProps.d.ts.map +1 -1
  274. package/lib/ir/ui/irChartProps.js +3 -2
  275. package/lib/ir/ui/irChartProps.js.map +1 -1
  276. package/lib/ir/ui/irCommandContext.d.ts +8 -0
  277. package/lib/ir/ui/irCommandContext.d.ts.map +1 -1
  278. package/lib/ir/ui/irCommandContext.js +14 -3
  279. package/lib/ir/ui/irCommandContext.js.map +1 -1
  280. package/lib/ir/ui/useIrEditor.d.ts +3 -3
  281. package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
  282. package/lib/ir/ui/useIrEditor.js +13 -4
  283. package/lib/ir/ui/useIrEditor.js.map +1 -1
  284. package/lib/ir/ui/useIrHandle.d.ts +14 -0
  285. package/lib/ir/ui/useIrHandle.d.ts.map +1 -0
  286. package/lib/ir/ui/useIrHandle.js +39 -0
  287. package/lib/ir/ui/useIrHandle.js.map +1 -0
  288. package/lib/ir/ui/useIrText.d.ts +40 -0
  289. package/lib/ir/ui/useIrText.d.ts.map +1 -0
  290. package/lib/ir/ui/useIrText.js +118 -0
  291. package/lib/ir/ui/useIrText.js.map +1 -0
  292. package/lib/ir/ui/useIrZoom.d.ts +7 -0
  293. package/lib/ir/ui/useIrZoom.d.ts.map +1 -1
  294. package/lib/ir/ui/useIrZoom.js +5 -4
  295. package/lib/ir/ui/useIrZoom.js.map +1 -1
  296. package/lib/ir/ui/useValueAxisZoom.d.ts +20 -0
  297. package/lib/ir/ui/useValueAxisZoom.d.ts.map +1 -0
  298. package/lib/ir/ui/useValueAxisZoom.js +54 -0
  299. package/lib/ir/ui/useValueAxisZoom.js.map +1 -0
  300. package/lib/ir.d.ts +3 -0
  301. package/lib/ir.d.ts.map +1 -1
  302. package/lib/ir.js +3 -0
  303. package/lib/ir.js.map +1 -1
  304. package/lib/locales/de.json +57 -1
  305. package/lib/locales/en.json +57 -1
  306. package/lib/locales/es.json +57 -1
  307. package/lib/locales/fr.json +57 -1
  308. package/lib/locales/it.json +57 -1
  309. package/lib/moleculesClient/core/index.d.ts +5 -0
  310. package/lib/moleculesClient/core/index.d.ts.map +1 -0
  311. package/lib/moleculesClient/core/index.js +3 -0
  312. package/lib/moleculesClient/core/index.js.map +1 -0
  313. package/lib/moleculesClient/core/moleculesClient.d.ts +12 -0
  314. package/lib/moleculesClient/core/moleculesClient.d.ts.map +1 -0
  315. package/lib/moleculesClient/core/moleculesClient.js +105 -0
  316. package/lib/moleculesClient/core/moleculesClient.js.map +1 -0
  317. package/lib/moleculesClient/core/moleculesClientApi.d.ts +100 -0
  318. package/lib/moleculesClient/core/moleculesClientApi.d.ts.map +1 -0
  319. package/lib/moleculesClient/core/moleculesClientApi.js +20 -0
  320. package/lib/moleculesClient/core/moleculesClientApi.js.map +1 -0
  321. package/lib/moleculesClient/core/moleculesTypes.d.ts +154 -0
  322. package/lib/moleculesClient/core/moleculesTypes.d.ts.map +1 -0
  323. package/lib/moleculesClient/core/moleculesTypes.js +2 -0
  324. package/lib/moleculesClient/core/moleculesTypes.js.map +1 -0
  325. package/lib/moleculesClient/core/requestRetry.d.ts +50 -0
  326. package/lib/moleculesClient/core/requestRetry.d.ts.map +1 -0
  327. package/lib/moleculesClient/core/requestRetry.js +108 -0
  328. package/lib/moleculesClient/core/requestRetry.js.map +1 -0
  329. package/lib/molstar/core/camera.d.ts +2 -1
  330. package/lib/molstar/core/camera.d.ts.map +1 -1
  331. package/lib/molstar/core/camera.js +3 -2
  332. package/lib/molstar/core/camera.js.map +1 -1
  333. package/lib/molstar/core/framing.d.ts +102 -0
  334. package/lib/molstar/core/framing.d.ts.map +1 -0
  335. package/lib/molstar/core/framing.js +120 -0
  336. package/lib/molstar/core/framing.js.map +1 -0
  337. package/lib/molstar/core/hover.d.ts +16 -0
  338. package/lib/molstar/core/hover.d.ts.map +1 -1
  339. package/lib/molstar/core/hover.js +14 -0
  340. package/lib/molstar/core/hover.js.map +1 -1
  341. package/lib/molstar/core/index.d.ts +4 -1
  342. package/lib/molstar/core/index.d.ts.map +1 -1
  343. package/lib/molstar/core/index.js +2 -1
  344. package/lib/molstar/core/index.js.map +1 -1
  345. package/lib/pedagogy/core/answers.d.ts +46 -0
  346. package/lib/pedagogy/core/answers.d.ts.map +1 -0
  347. package/lib/pedagogy/core/answers.js +77 -0
  348. package/lib/pedagogy/core/answers.js.map +1 -0
  349. package/lib/pedagogy/core/attempts.d.ts +86 -0
  350. package/lib/pedagogy/core/attempts.d.ts.map +1 -0
  351. package/lib/pedagogy/core/attempts.js +117 -0
  352. package/lib/pedagogy/core/attempts.js.map +1 -0
  353. package/lib/pedagogy/core/index.d.ts +8 -0
  354. package/lib/pedagogy/core/index.d.ts.map +1 -1
  355. package/lib/pedagogy/core/index.js +4 -0
  356. package/lib/pedagogy/core/index.js.map +1 -1
  357. package/lib/pedagogy/core/progressController.d.ts +64 -0
  358. package/lib/pedagogy/core/progressController.d.ts.map +1 -0
  359. package/lib/pedagogy/core/progressController.js +56 -0
  360. package/lib/pedagogy/core/progressController.js.map +1 -0
  361. package/lib/pedagogy/core/seed.d.ts +96 -0
  362. package/lib/pedagogy/core/seed.d.ts.map +1 -0
  363. package/lib/pedagogy/core/seed.js +128 -0
  364. package/lib/pedagogy/core/seed.js.map +1 -0
  365. package/lib/pedagogy/core/series.d.ts +77 -0
  366. package/lib/pedagogy/core/series.d.ts.map +1 -0
  367. package/lib/pedagogy/core/series.js +10 -0
  368. package/lib/pedagogy/core/series.js.map +1 -0
  369. package/lib/pedagogy/ui/AnswerFields.d.ts +21 -0
  370. package/lib/pedagogy/ui/AnswerFields.d.ts.map +1 -0
  371. package/lib/pedagogy/ui/AnswerFields.js +24 -0
  372. package/lib/pedagogy/ui/AnswerFields.js.map +1 -0
  373. package/lib/pedagogy/ui/ExerciseList.d.ts +82 -0
  374. package/lib/pedagogy/ui/ExerciseList.d.ts.map +1 -0
  375. package/lib/pedagogy/ui/ExerciseList.js +53 -0
  376. package/lib/pedagogy/ui/ExerciseList.js.map +1 -0
  377. package/lib/pedagogy/ui/ExerciseSeries.d.ts +95 -0
  378. package/lib/pedagogy/ui/ExerciseSeries.d.ts.map +1 -0
  379. package/lib/pedagogy/ui/ExerciseSeries.js +74 -0
  380. package/lib/pedagogy/ui/ExerciseSeries.js.map +1 -0
  381. package/lib/pedagogy/ui/QuestionCard.d.ts +64 -0
  382. package/lib/pedagogy/ui/QuestionCard.d.ts.map +1 -0
  383. package/lib/pedagogy/ui/QuestionCard.js +73 -0
  384. package/lib/pedagogy/ui/QuestionCard.js.map +1 -0
  385. package/lib/pedagogy/ui/index.d.ts +10 -0
  386. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  387. package/lib/pedagogy/ui/index.js +6 -0
  388. package/lib/pedagogy/ui/index.js.map +1 -1
  389. package/lib/pedagogy/ui/seriesCounts.d.ts +17 -0
  390. package/lib/pedagogy/ui/seriesCounts.d.ts.map +1 -0
  391. package/lib/pedagogy/ui/seriesCounts.js +27 -0
  392. package/lib/pedagogy/ui/seriesCounts.js.map +1 -0
  393. package/lib/pedagogy/ui/seriesParts.d.ts +55 -0
  394. package/lib/pedagogy/ui/seriesParts.d.ts.map +1 -0
  395. package/lib/pedagogy/ui/seriesParts.js +38 -0
  396. package/lib/pedagogy/ui/seriesParts.js.map +1 -0
  397. package/lib/pedagogy/ui/useAttemptRecords.d.ts +10 -0
  398. package/lib/pedagogy/ui/useAttemptRecords.d.ts.map +1 -0
  399. package/lib/pedagogy/ui/useAttemptRecords.js +11 -0
  400. package/lib/pedagogy/ui/useAttemptRecords.js.map +1 -0
  401. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  402. package/lib/periodic/ui/PeriodicTable.js +6 -3
  403. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  404. package/lib/property/core/copyableText.d.ts +14 -0
  405. package/lib/property/core/copyableText.d.ts.map +1 -0
  406. package/lib/property/core/copyableText.js +21 -0
  407. package/lib/property/core/copyableText.js.map +1 -0
  408. package/lib/property/core/index.d.ts +2 -0
  409. package/lib/property/core/index.d.ts.map +1 -0
  410. package/lib/property/core/index.js +2 -0
  411. package/lib/property/core/index.js.map +1 -0
  412. package/lib/property/ui/PropertyTable.d.ts +43 -0
  413. package/lib/property/ui/PropertyTable.d.ts.map +1 -0
  414. package/lib/property/ui/PropertyTable.js +19 -0
  415. package/lib/property/ui/PropertyTable.js.map +1 -0
  416. package/lib/property/ui/index.d.ts +3 -0
  417. package/lib/property/ui/index.d.ts.map +1 -0
  418. package/lib/property/ui/index.js +2 -0
  419. package/lib/property/ui/index.js.map +1 -0
  420. package/lib/raman.d.ts +16 -0
  421. package/lib/raman.d.ts.map +1 -0
  422. package/lib/raman.js +12 -0
  423. package/lib/raman.js.map +1 -0
  424. package/lib/router/core/history.d.ts +24 -3
  425. package/lib/router/core/history.d.ts.map +1 -1
  426. package/lib/router/core/history.js +55 -7
  427. package/lib/router/core/history.js.map +1 -1
  428. package/lib/router/core/index.d.ts +3 -3
  429. package/lib/router/core/index.d.ts.map +1 -1
  430. package/lib/router/core/index.js +2 -2
  431. package/lib/router/core/index.js.map +1 -1
  432. package/lib/router/core/languageRoute.d.ts +61 -0
  433. package/lib/router/core/languageRoute.d.ts.map +1 -0
  434. package/lib/router/core/languageRoute.js +96 -0
  435. package/lib/router/core/languageRoute.js.map +1 -0
  436. package/lib/router/core/siteAddresses.d.ts +23 -0
  437. package/lib/router/core/siteAddresses.d.ts.map +1 -1
  438. package/lib/router/core/siteAddresses.js +26 -0
  439. package/lib/router/core/siteAddresses.js.map +1 -1
  440. package/lib/router/core/tabRouter.d.ts +2 -108
  441. package/lib/router/core/tabRouter.d.ts.map +1 -1
  442. package/lib/router/core/tabRouter.js +38 -5
  443. package/lib/router/core/tabRouter.js.map +1 -1
  444. package/lib/router/core/tabRouterTypes.d.ts +154 -0
  445. package/lib/router/core/tabRouterTypes.d.ts.map +1 -0
  446. package/lib/router/core/tabRouterTypes.js +2 -0
  447. package/lib/router/core/tabRouterTypes.js.map +1 -0
  448. package/lib/seo/core/fitDescription.d.ts +40 -0
  449. package/lib/seo/core/fitDescription.d.ts.map +1 -0
  450. package/lib/seo/core/fitDescription.js +45 -0
  451. package/lib/seo/core/fitDescription.js.map +1 -0
  452. package/lib/seo/core/index.d.ts +7 -0
  453. package/lib/seo/core/index.d.ts.map +1 -1
  454. package/lib/seo/core/index.js +4 -0
  455. package/lib/seo/core/index.js.map +1 -1
  456. package/lib/seo/core/limits.d.ts +24 -0
  457. package/lib/seo/core/limits.d.ts.map +1 -0
  458. package/lib/seo/core/limits.js +24 -0
  459. package/lib/seo/core/limits.js.map +1 -0
  460. package/lib/seo/core/pageContent.d.ts +25 -0
  461. package/lib/seo/core/pageContent.d.ts.map +1 -0
  462. package/lib/seo/core/pageContent.js +25 -0
  463. package/lib/seo/core/pageContent.js.map +1 -0
  464. package/lib/seo/core/plainDescription.d.ts.map +1 -1
  465. package/lib/seo/core/plainDescription.js +3 -2
  466. package/lib/seo/core/plainDescription.js.map +1 -1
  467. package/lib/seo/core/routeProblems.d.ts.map +1 -1
  468. package/lib/seo/core/routeProblems.js +1 -6
  469. package/lib/seo/core/routeProblems.js.map +1 -1
  470. package/lib/seo/core/routeTable.d.ts +31 -0
  471. package/lib/seo/core/routeTable.d.ts.map +1 -0
  472. package/lib/seo/core/routeTable.js +96 -0
  473. package/lib/seo/core/routeTable.js.map +1 -0
  474. package/lib/seo/vite/index.d.ts +2 -0
  475. package/lib/seo/vite/index.d.ts.map +1 -1
  476. package/lib/seo/vite/index.js +1 -0
  477. package/lib/seo/vite/index.js.map +1 -1
  478. package/lib/seo/vite/prerender.d.ts +10 -0
  479. package/lib/seo/vite/prerender.d.ts.map +1 -1
  480. package/lib/seo/vite/prerender.js +12 -1
  481. package/lib/seo/vite/prerender.js.map +1 -1
  482. package/lib/seo/vite/routeTable.d.ts +40 -0
  483. package/lib/seo/vite/routeTable.d.ts.map +1 -0
  484. package/lib/seo/vite/routeTable.js +44 -0
  485. package/lib/seo/vite/routeTable.js.map +1 -0
  486. package/lib/server/answerAddresses.d.ts +51 -0
  487. package/lib/server/answerAddresses.d.ts.map +1 -0
  488. package/lib/server/answerAddresses.js +72 -0
  489. package/lib/server/answerAddresses.js.map +1 -0
  490. package/lib/server/cardMeta.d.ts +57 -0
  491. package/lib/server/cardMeta.d.ts.map +1 -0
  492. package/lib/server/cardMeta.js +52 -0
  493. package/lib/server/cardMeta.js.map +1 -0
  494. package/lib/server/config.d.ts +72 -0
  495. package/lib/server/config.d.ts.map +1 -0
  496. package/lib/server/config.js +67 -0
  497. package/lib/server/config.js.map +1 -0
  498. package/lib/server/envNumber.d.ts +35 -0
  499. package/lib/server/envNumber.d.ts.map +1 -0
  500. package/lib/server/envNumber.js +42 -0
  501. package/lib/server/envNumber.js.map +1 -0
  502. package/lib/server/healthRoute.d.ts +26 -0
  503. package/lib/server/healthRoute.d.ts.map +1 -0
  504. package/lib/server/healthRoute.js +22 -0
  505. package/lib/server/healthRoute.js.map +1 -0
  506. package/lib/server/listenSite.d.ts +38 -0
  507. package/lib/server/listenSite.d.ts.map +1 -0
  508. package/lib/server/listenSite.js +60 -0
  509. package/lib/server/listenSite.js.map +1 -0
  510. package/lib/server/mcpServer.d.ts +8 -0
  511. package/lib/server/mcpServer.d.ts.map +1 -0
  512. package/lib/server/mcpServer.js +11 -0
  513. package/lib/server/mcpServer.js.map +1 -0
  514. package/lib/server/repositoryVersion.d.ts +16 -0
  515. package/lib/server/repositoryVersion.d.ts.map +1 -0
  516. package/lib/server/repositoryVersion.js +33 -0
  517. package/lib/server/repositoryVersion.js.map +1 -0
  518. package/lib/server/routeOptions.d.ts +23 -0
  519. package/lib/server/routeOptions.d.ts.map +1 -0
  520. package/lib/server/routeOptions.js +20 -0
  521. package/lib/server/routeOptions.js.map +1 -0
  522. package/lib/server/routeTable.d.ts +14 -0
  523. package/lib/server/routeTable.d.ts.map +1 -0
  524. package/lib/server/routeTable.js +32 -0
  525. package/lib/server/routeTable.js.map +1 -0
  526. package/lib/server/siteView.d.ts +29 -0
  527. package/lib/server/siteView.d.ts.map +1 -0
  528. package/lib/server/siteView.js +21 -0
  529. package/lib/server/siteView.js.map +1 -0
  530. package/lib/server/spaPages.d.ts +32 -0
  531. package/lib/server/spaPages.d.ts.map +1 -0
  532. package/lib/server/spaPages.js +126 -0
  533. package/lib/server/spaPages.js.map +1 -0
  534. package/lib/server/spaSite.d.ts +30 -0
  535. package/lib/server/spaSite.d.ts.map +1 -0
  536. package/lib/server/spaSite.js +170 -0
  537. package/lib/server/spaSite.js.map +1 -0
  538. package/lib/server/spaSiteOptions.d.ts +126 -0
  539. package/lib/server/spaSiteOptions.d.ts.map +1 -0
  540. package/lib/server/spaSiteOptions.js +2 -0
  541. package/lib/server/spaSiteOptions.js.map +1 -0
  542. package/lib/server/staticSite.d.ts +9 -0
  543. package/lib/server/staticSite.d.ts.map +1 -1
  544. package/lib/server/staticSite.js +41 -19
  545. package/lib/server/staticSite.js.map +1 -1
  546. package/lib/server/toolSiteServer.d.ts +77 -0
  547. package/lib/server/toolSiteServer.d.ts.map +1 -0
  548. package/lib/server/toolSiteServer.js +58 -0
  549. package/lib/server/toolSiteServer.js.map +1 -0
  550. package/lib/server/trustProxy.d.ts +20 -0
  551. package/lib/server/trustProxy.d.ts.map +1 -0
  552. package/lib/server/trustProxy.js +32 -0
  553. package/lib/server/trustProxy.js.map +1 -0
  554. package/lib/server/types.d.ts +13 -0
  555. package/lib/server/types.d.ts.map +1 -0
  556. package/lib/server/types.js +2 -0
  557. package/lib/server/types.js.map +1 -0
  558. package/lib/server.d.ts +22 -0
  559. package/lib/server.d.ts.map +1 -1
  560. package/lib/server.js +12 -0
  561. package/lib/server.js.map +1 -1
  562. package/lib/share/core/config.d.ts +18 -0
  563. package/lib/share/core/config.d.ts.map +1 -1
  564. package/lib/share/core/config.js +33 -2
  565. package/lib/share/core/config.js.map +1 -1
  566. package/lib/share/core/index.d.ts +3 -1
  567. package/lib/share/core/index.d.ts.map +1 -1
  568. package/lib/share/core/index.js +2 -1
  569. package/lib/share/core/index.js.map +1 -1
  570. package/lib/share/core/keySetParam.d.ts +40 -0
  571. package/lib/share/core/keySetParam.d.ts.map +1 -0
  572. package/lib/share/core/keySetParam.js +60 -0
  573. package/lib/share/core/keySetParam.js.map +1 -0
  574. package/lib/share/core/vocabulary.d.ts +8 -0
  575. package/lib/share/core/vocabulary.d.ts.map +1 -1
  576. package/lib/shell/ui/ShareControl.d.ts +75 -0
  577. package/lib/shell/ui/ShareControl.d.ts.map +1 -0
  578. package/lib/shell/ui/ShareControl.js +40 -0
  579. package/lib/shell/ui/ShareControl.js.map +1 -0
  580. package/lib/shell/ui/ShellFrame.d.ts +14 -0
  581. package/lib/shell/ui/ShellFrame.d.ts.map +1 -0
  582. package/lib/shell/ui/ShellFrame.js +45 -0
  583. package/lib/shell/ui/ShellFrame.js.map +1 -0
  584. package/lib/shell/ui/SiteShell.d.ts +251 -0
  585. package/lib/shell/ui/SiteShell.d.ts.map +1 -0
  586. package/lib/shell/ui/SiteShell.js +39 -0
  587. package/lib/shell/ui/SiteShell.js.map +1 -0
  588. package/lib/shell/ui/index.d.ts +5 -0
  589. package/lib/shell/ui/index.d.ts.map +1 -0
  590. package/lib/shell/ui/index.js +3 -0
  591. package/lib/shell/ui/index.js.map +1 -0
  592. package/lib/state/core/index.d.ts +1 -0
  593. package/lib/state/core/index.d.ts.map +1 -1
  594. package/lib/state/core/index.js.map +1 -1
  595. package/lib/state/core/legacyEntries.d.ts +30 -0
  596. package/lib/state/core/legacyEntries.d.ts.map +1 -0
  597. package/lib/state/core/legacyEntries.js +51 -0
  598. package/lib/state/core/legacyEntries.js.map +1 -0
  599. package/lib/state/core/persistBucket.d.ts +26 -2
  600. package/lib/state/core/persistBucket.d.ts.map +1 -1
  601. package/lib/state/core/persistBucket.js +26 -9
  602. package/lib/state/core/persistBucket.js.map +1 -1
  603. package/lib/state/core/persistSignalBucket.d.ts +26 -0
  604. package/lib/state/core/persistSignalBucket.d.ts.map +1 -1
  605. package/lib/state/core/persistSignalBucket.js +31 -0
  606. package/lib/state/core/persistSignalBucket.js.map +1 -1
  607. package/lib/state/core/storageEntry.d.ts +15 -0
  608. package/lib/state/core/storageEntry.d.ts.map +1 -1
  609. package/lib/state/core/storageEntry.js +33 -0
  610. package/lib/state/core/storageEntry.js.map +1 -1
  611. package/lib/structure/ui/StructureExportButton.d.ts +27 -0
  612. package/lib/structure/ui/StructureExportButton.d.ts.map +1 -0
  613. package/lib/structure/ui/StructureExportButton.js +21 -0
  614. package/lib/structure/ui/StructureExportButton.js.map +1 -0
  615. package/lib/structure/ui/index.d.ts +4 -0
  616. package/lib/structure/ui/index.d.ts.map +1 -1
  617. package/lib/structure/ui/index.js +2 -0
  618. package/lib/structure/ui/index.js.map +1 -1
  619. package/lib/structure/ui/useStructureDraft.d.ts +32 -0
  620. package/lib/structure/ui/useStructureDraft.d.ts.map +1 -0
  621. package/lib/structure/ui/useStructureDraft.js +20 -0
  622. package/lib/structure/ui/useStructureDraft.js.map +1 -0
  623. package/lib/ui.d.ts +2 -0
  624. package/lib/ui.d.ts.map +1 -1
  625. package/lib/ui.js +2 -0
  626. package/lib/ui.js.map +1 -1
  627. package/lib/worker/core/index.d.ts +1 -1
  628. package/lib/worker/core/index.d.ts.map +1 -1
  629. package/lib/worker/core/messages.d.ts +4 -2
  630. package/lib/worker/core/messages.d.ts.map +1 -1
  631. package/lib/worker/core/messages.js.map +1 -1
  632. package/lib/worker/core/oclResourcesUrl.d.ts +16 -0
  633. package/lib/worker/core/oclResourcesUrl.d.ts.map +1 -0
  634. package/lib/worker/core/oclResourcesUrl.js +19 -0
  635. package/lib/worker/core/oclResourcesUrl.js.map +1 -0
  636. package/lib/worker/core/serveWorkerRequests.d.ts +8 -0
  637. package/lib/worker/core/serveWorkerRequests.d.ts.map +1 -1
  638. package/lib/worker/core/serveWorkerRequests.js +15 -2
  639. package/lib/worker/core/serveWorkerRequests.js.map +1 -1
  640. package/lib/worker/core/workerChannel.d.ts +3 -4
  641. package/lib/worker/core/workerChannel.d.ts.map +1 -1
  642. package/lib/worker/core/workerChannel.js +72 -67
  643. package/lib/worker/core/workerChannel.js.map +1 -1
  644. package/lib/worker/core/workerChannelParts.d.ts +17 -6
  645. package/lib/worker/core/workerChannelParts.d.ts.map +1 -1
  646. package/lib/worker/core/workerChannelParts.js +20 -4
  647. package/lib/worker/core/workerChannelParts.js.map +1 -1
  648. package/lib/worker/core/workerChannelTypes.d.ts +46 -2
  649. package/lib/worker/core/workerChannelTypes.d.ts.map +1 -1
  650. package/lib/worker/core/workerSlot.d.ts +66 -0
  651. package/lib/worker/core/workerSlot.d.ts.map +1 -0
  652. package/lib/worker/core/workerSlot.js +107 -0
  653. package/lib/worker/core/workerSlot.js.map +1 -0
  654. package/package.json +17 -1
  655. package/src/card/core/cardAddress.ts +100 -0
  656. package/src/card/core/cardPageUrl.ts +97 -0
  657. package/src/card/core/index.ts +6 -0
  658. package/src/card/core/panelRoom.ts +66 -0
  659. package/src/card/ui/CardDetailsButton.tsx +104 -0
  660. package/src/card/ui/CardFigure.tsx +86 -0
  661. package/src/card/ui/CardFrame.tsx +46 -0
  662. package/src/card/ui/CopyTableButton.tsx +81 -0
  663. package/src/card/ui/cardTooltip.ts +18 -0
  664. package/src/card/ui/embed.ts +27 -0
  665. package/src/card/ui/fitCardToFrame.ts +76 -0
  666. package/src/card/ui/holdRoomForPanels.ts +83 -0
  667. package/src/card/ui/index.ts +14 -0
  668. package/src/card/ui/openPanels.ts +106 -0
  669. package/src/card.ts +13 -0
  670. package/src/conformers.ts +4 -0
  671. package/src/core.ts +5 -0
  672. package/src/fetch/core/apiError.ts +65 -0
  673. package/src/fetch/core/fetchJson.ts +129 -0
  674. package/src/fetch/core/index.ts +4 -0
  675. package/src/formula/core/formulaText.ts +96 -0
  676. package/src/formula/core/index.ts +20 -0
  677. package/src/formula/core/normalizeFormula.ts +50 -0
  678. package/src/formula/core/readFormula.ts +211 -0
  679. package/src/formula/ui/CopyableFormula.tsx +51 -0
  680. package/src/formula/ui/FormulaInput.tsx +50 -0
  681. package/src/formula/ui/QuestionFormula.tsx +20 -0
  682. package/src/formula/ui/index.ts +6 -0
  683. package/src/formula.ts +11 -0
  684. package/src/hooks/ui/index.ts +1 -0
  685. package/src/hooks/ui/keyTargets.ts +5 -3
  686. package/src/hooks/ui/useAsync.ts +50 -14
  687. package/src/ir/core/analysisSpectra.ts +26 -10
  688. package/src/ir/core/bandLabelPlan.ts +21 -10
  689. package/src/ir/core/index.ts +25 -5
  690. package/src/ir/core/irBand.ts +52 -14
  691. package/src/ir/core/irCommands.ts +15 -1
  692. package/src/ir/core/irDomain.ts +9 -7
  693. package/src/ir/core/irFormat.ts +39 -6
  694. package/src/ir/core/irMode.ts +42 -10
  695. package/src/ir/core/irReducer.ts +1 -49
  696. package/src/ir/core/irSpectrum.ts +59 -30
  697. package/src/ir/core/irState.ts +67 -2
  698. package/src/ir/core/irTechnique.ts +115 -0
  699. package/src/ir/core/irTechniqueCommands.ts +82 -0
  700. package/src/ir/core/pickBands.ts +63 -28
  701. package/src/ir/core/ramanBands.ts +105 -0
  702. package/src/ir/core/spectrumJcamp.ts +65 -16
  703. package/src/ir/core/toIrSpectrum.ts +20 -2
  704. package/src/ir/ui/BandRow.tsx +107 -0
  705. package/src/ir/ui/BandsPanel.tsx +32 -125
  706. package/src/ir/ui/IrAboutDialog.tsx +69 -28
  707. package/src/ir/ui/IrCanvas.tsx +2 -1
  708. package/src/ir/ui/IrChart.tsx +20 -24
  709. package/src/ir/ui/IrCommandProvider.tsx +10 -3
  710. package/src/ir/ui/IrCommandTooltip.tsx +11 -2
  711. package/src/ir/ui/IrDocumentationDialog.tsx +99 -55
  712. package/src/ir/ui/IrEditor.tsx +5 -36
  713. package/src/ir/ui/IrHeader.tsx +10 -3
  714. package/src/ir/ui/IrLogo.tsx +28 -9
  715. package/src/ir/ui/IrShell.tsx +27 -75
  716. package/src/ir/ui/IrStatusBar.tsx +17 -12
  717. package/src/ir/ui/IrToolbar.tsx +26 -15
  718. package/src/ir/ui/IrTraces.tsx +5 -1
  719. package/src/ir/ui/RamanEditor.tsx +53 -0
  720. package/src/ir/ui/SpectraPanel.tsx +2 -1
  721. package/src/ir/ui/SpectrumRow.tsx +14 -5
  722. package/src/ir/ui/VibrationalEditor.tsx +94 -0
  723. package/src/ir/ui/bandsTsv.ts +46 -0
  724. package/src/ir/ui/irChartProps.ts +14 -4
  725. package/src/ir/ui/irCommandContext.tsx +18 -3
  726. package/src/ir/ui/useIrEditor.ts +20 -8
  727. package/src/ir/ui/useIrHandle.ts +51 -0
  728. package/src/ir/ui/useIrText.ts +170 -0
  729. package/src/ir/ui/useIrZoom.ts +12 -3
  730. package/src/ir/ui/useValueAxisZoom.ts +67 -0
  731. package/src/ir.ts +3 -0
  732. package/src/locales/de.json +57 -1
  733. package/src/locales/en.json +57 -1
  734. package/src/locales/es.json +57 -1
  735. package/src/locales/fr.json +57 -1
  736. package/src/locales/it.json +57 -1
  737. package/src/moleculesClient/core/index.ts +19 -0
  738. package/src/moleculesClient/core/moleculesClient.ts +175 -0
  739. package/src/moleculesClient/core/moleculesClientApi.ts +120 -0
  740. package/src/moleculesClient/core/moleculesTypes.ts +163 -0
  741. package/src/moleculesClient/core/requestRetry.ts +118 -0
  742. package/src/molstar/core/camera.ts +3 -2
  743. package/src/molstar/core/framing.ts +200 -0
  744. package/src/molstar/core/hover.ts +26 -0
  745. package/src/molstar/core/index.ts +21 -1
  746. package/src/pedagogy/core/answers.ts +94 -0
  747. package/src/pedagogy/core/attempts.ts +205 -0
  748. package/src/pedagogy/core/index.ts +36 -0
  749. package/src/pedagogy/core/progressController.ts +116 -0
  750. package/src/pedagogy/core/seed.ts +177 -0
  751. package/src/pedagogy/core/series.ts +82 -0
  752. package/src/pedagogy/ui/AnswerFields.tsx +63 -0
  753. package/src/pedagogy/ui/ExerciseList.tsx +202 -0
  754. package/src/pedagogy/ui/ExerciseSeries.tsx +250 -0
  755. package/src/pedagogy/ui/QuestionCard.tsx +231 -0
  756. package/src/pedagogy/ui/index.ts +18 -0
  757. package/src/pedagogy/ui/seriesCounts.ts +34 -0
  758. package/src/pedagogy/ui/seriesParts.tsx +127 -0
  759. package/src/pedagogy/ui/useAttemptRecords.ts +16 -0
  760. package/src/periodic/ui/PeriodicTable.tsx +6 -3
  761. package/src/property/core/copyableText.ts +20 -0
  762. package/src/property/core/index.ts +1 -0
  763. package/src/property/ui/PropertyTable.tsx +83 -0
  764. package/src/property/ui/index.ts +2 -0
  765. package/src/raman.ts +19 -0
  766. package/src/router/core/history.ts +61 -7
  767. package/src/router/core/index.ts +3 -2
  768. package/src/router/core/languageRoute.ts +136 -0
  769. package/src/router/core/siteAddresses.ts +38 -0
  770. package/src/router/core/tabRouter.ts +59 -117
  771. package/src/router/core/tabRouterTypes.ts +158 -0
  772. package/src/seo/core/fitDescription.ts +74 -0
  773. package/src/seo/core/index.ts +17 -0
  774. package/src/seo/core/limits.ts +27 -0
  775. package/src/seo/core/pageContent.ts +42 -0
  776. package/src/seo/core/plainDescription.ts +4 -2
  777. package/src/seo/core/routeProblems.ts +1 -7
  778. package/src/seo/core/routeTable.ts +103 -0
  779. package/src/seo/vite/index.ts +2 -0
  780. package/src/seo/vite/prerender.ts +26 -1
  781. package/src/seo/vite/routeTable.ts +79 -0
  782. package/src/server/answerAddresses.ts +92 -0
  783. package/src/server/cardMeta.ts +88 -0
  784. package/src/server/config.ts +125 -0
  785. package/src/server/envNumber.ts +65 -0
  786. package/src/server/healthRoute.ts +42 -0
  787. package/src/server/listenSite.ts +90 -0
  788. package/src/server/mcpServer.ts +14 -0
  789. package/src/server/repositoryVersion.ts +33 -0
  790. package/src/server/routeOptions.ts +26 -0
  791. package/src/server/routeTable.ts +35 -0
  792. package/src/server/siteView.ts +42 -0
  793. package/src/server/spaPages.ts +179 -0
  794. package/src/server/spaSite.ts +216 -0
  795. package/src/server/spaSiteOptions.ts +133 -0
  796. package/src/server/staticSite.ts +65 -35
  797. package/src/server/toolSiteServer.ts +127 -0
  798. package/src/server/trustProxy.ts +32 -0
  799. package/src/server/types.ts +25 -0
  800. package/src/server.ts +40 -0
  801. package/src/share/core/config.ts +45 -2
  802. package/src/share/core/index.ts +4 -0
  803. package/src/share/core/keySetParam.ts +92 -0
  804. package/src/share/core/vocabulary.ts +8 -0
  805. package/src/shell/ui/ShareControl.tsx +150 -0
  806. package/src/shell/ui/ShellFrame.tsx +180 -0
  807. package/src/shell/ui/SiteShell.tsx +297 -0
  808. package/src/shell/ui/index.ts +9 -0
  809. package/src/state/core/index.ts +1 -0
  810. package/src/state/core/legacyEntries.ts +76 -0
  811. package/src/state/core/persistBucket.ts +50 -10
  812. package/src/state/core/persistSignalBucket.ts +52 -0
  813. package/src/state/core/storageEntry.ts +32 -0
  814. package/src/structure/ui/StructureExportButton.tsx +57 -0
  815. package/src/structure/ui/index.ts +4 -0
  816. package/src/structure/ui/useStructureDraft.ts +47 -0
  817. package/src/ui.ts +2 -0
  818. package/src/worker/core/index.ts +1 -0
  819. package/src/worker/core/messages.ts +4 -3
  820. package/src/worker/core/oclResourcesUrl.ts +21 -0
  821. package/src/worker/core/serveWorkerRequests.ts +30 -2
  822. package/src/worker/core/workerChannel.ts +74 -74
  823. package/src/worker/core/workerChannelParts.ts +33 -13
  824. package/src/worker/core/workerChannelTypes.ts +47 -2
  825. package/src/worker/core/workerSlot.ts +181 -0
  826. package/styles/card.css +145 -0
  827. package/styles/chrome.css +248 -0
@@ -0,0 +1,90 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+
3
+ /** Options of {@link listenSite}. */
4
+ export interface ListenSiteOptions {
5
+ /** The port to listen on. */
6
+ port: number;
7
+ /**
8
+ * The interface to listen on.
9
+ * @default '0.0.0.0' - every interface, as a container needs
10
+ */
11
+ host?: string;
12
+ /**
13
+ * Run once the server has closed on a signal: stop what the server does not
14
+ * own itself, such as a scheduler or a write queue started beside it.
15
+ * @default undefined - nothing more is stopped
16
+ */
17
+ onClose?: () => void | Promise<void>;
18
+ /**
19
+ * The signals that close the server.
20
+ * @default ['SIGTERM', 'SIGINT'] - what `docker stop` and a terminal send
21
+ */
22
+ signals?: readonly NodeJS.Signals[];
23
+ }
24
+
25
+ /**
26
+ * Listen, and close cleanly when the container is stopped.
27
+ *
28
+ * On the first signal the server closes — its `onClose` hooks stop the worker
29
+ * pools it owns — then `onClose` runs. A close that fails is logged and leaves
30
+ * `process.exitCode` at 1 rather than surfacing as an unhandled rejection, and
31
+ * the process ends on its own once nothing is left running. A server that
32
+ * cannot listen is logged, closed and reported the same way.
33
+ *
34
+ * await listenSite(app, { port: config.port, host: config.host });
35
+ * @param app - The server, built and not yet listening.
36
+ * @param options - Where to listen, and what else to stop.
37
+ * @throws {Error} When the server cannot listen, after it has been closed.
38
+ */
39
+ export async function listenSite(
40
+ app: FastifyInstance,
41
+ options: ListenSiteOptions,
42
+ ): Promise<void> {
43
+ const {
44
+ port,
45
+ host = '0.0.0.0',
46
+ onClose,
47
+ signals = ['SIGTERM', 'SIGINT'],
48
+ } = options;
49
+
50
+ const stop = () => {
51
+ for (const signal of signals) process.off(signal, stop);
52
+ void shutDown(app, onClose);
53
+ };
54
+ for (const signal of signals) process.once(signal, stop);
55
+
56
+ try {
57
+ await app.listen({ port, host });
58
+ } catch (error) {
59
+ for (const signal of signals) process.off(signal, stop);
60
+ app.log.error(error, `the server could not listen on ${host}:${port}`);
61
+ process.exitCode = 1;
62
+ await shutDown(app, onClose);
63
+ throw error;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Close the server, then run what else has to stop, reporting a failure of
69
+ * either through the log and the exit code.
70
+ * @param app - The server.
71
+ * @param onClose - What else to stop.
72
+ */
73
+ async function shutDown(
74
+ app: FastifyInstance,
75
+ onClose: (() => void | Promise<void>) | undefined,
76
+ ): Promise<void> {
77
+ try {
78
+ await app.close();
79
+ } catch (error) {
80
+ app.log.error(error, 'the server did not close cleanly');
81
+ process.exitCode = 1;
82
+ }
83
+ if (onClose === undefined) return;
84
+ try {
85
+ await onClose();
86
+ } catch (error) {
87
+ app.log.error(error, 'what runs beside the server did not stop cleanly');
88
+ process.exitCode = 1;
89
+ }
90
+ }
@@ -0,0 +1,14 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ import type * as McpServer from 'cheminfo-mcp-server';
4
+
5
+ const require = createRequire(import.meta.url);
6
+
7
+ /**
8
+ * `cheminfo-mcp-server`, an optional peer, loaded when a helper first needs
9
+ * it, so `react-cheminfo/server` imports on a site that serves no tools.
10
+ * @returns The module.
11
+ */
12
+ export function mcpServer(): typeof McpServer {
13
+ return require('cheminfo-mcp-server') as typeof McpServer;
14
+ }
@@ -0,0 +1,33 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ import { UNRELEASED_VERSION } from '../build/core/buildInfo.ts';
5
+ import { findRepositoryRoot } from '../build/vite/buildInfo.ts';
6
+
7
+ /**
8
+ * The release a server's repository is at, as release-please writes it.
9
+ *
10
+ * Read from the `package.json` at the repository root, found by the same
11
+ * climbing rule `cheminfoBuildInfo` follows: a `backend` or `server` directory
12
+ * keeps the `0.0.0` it was scaffolded with, or none at all, while the root is
13
+ * the manifest a release bumps. A manifest that cannot be read is not a reason
14
+ * to refuse to start, so it reads as unreleased instead.
15
+ *
16
+ * const version = readRepositoryVersion(import.meta.dirname);
17
+ * @param fromDirectory - Where to start climbing, usually the server's own
18
+ * directory.
19
+ * @returns The version, or `'0.0.0'` when the root manifest carries none.
20
+ */
21
+ export function readRepositoryVersion(fromDirectory: string): string {
22
+ const root = findRepositoryRoot(fromDirectory);
23
+ let manifest: unknown;
24
+ try {
25
+ manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
26
+ } catch {
27
+ return UNRELEASED_VERSION;
28
+ }
29
+ const version = (manifest as { version?: unknown } | null)?.version;
30
+ return typeof version === 'string' && version !== ''
31
+ ? version
32
+ : UNRELEASED_VERSION;
33
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * What every route the serving helpers register shares: how it is cached, who
3
+ * may read it, and that it stays out of the API's documentation.
4
+ */
5
+
6
+ import type { FastifySchema } from 'fastify';
7
+
8
+ /** A page is checked on every visit: it names the bundles of its own build. */
9
+ export const PAGE_CACHE = 'no-cache';
10
+
11
+ /** A bundle is named by its content, so it never changes under its name. */
12
+ export const BUNDLE_CACHE = 'public, max-age=31536000, immutable';
13
+
14
+ /**
15
+ * The header that opens an answer to every origin. Every file of a build is
16
+ * public, and a page framed by a sandboxed view runs under an opaque origin,
17
+ * where everything it fetches from its own site is cross-origin: the static
18
+ * hosts open every response, and so do these servers.
19
+ */
20
+ export const ALLOW_ORIGIN = 'access-control-allow-origin';
21
+
22
+ /** Kept out of the API's documentation (`@fastify/swagger` reads `hide`). */
23
+ export const HIDDEN: FastifySchema & { hide: boolean } = { hide: true };
24
+
25
+ /** The addresses an API and its documentation answer, never a page. */
26
+ export const DEFAULT_RESERVED: readonly string[] = ['/v1/', '/docs'];
@@ -0,0 +1,35 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ import { ROUTE_TABLE_FILE, parseRouteTable } from '../seo/core/routeTable.ts';
5
+ import type { RouteMeta } from '../seo/core/routes.ts';
6
+
7
+ /**
8
+ * Every address the frontend routes itself, from the `routes.json` its build
9
+ * wrote beside the page (`cheminfoRouteTable` in `react-cheminfo/vite`).
10
+ *
11
+ * The pages that exist whatever the build wrote are the fallback, so a server
12
+ * started before the frontend was built, or against a build of an older shape,
13
+ * still titles them.
14
+ * @param root - The directory holding the built frontend.
15
+ * @param fallback - The routes when the build wrote no table this can read.
16
+ * @returns The routes, the home page first.
17
+ */
18
+ export function readRouteTable(
19
+ root: string,
20
+ fallback: readonly RouteMeta[],
21
+ ): RouteMeta[] {
22
+ let text: string;
23
+ try {
24
+ text = readFileSync(join(root, ROUTE_TABLE_FILE), 'utf8');
25
+ } catch {
26
+ return [...fallback];
27
+ }
28
+ let parsed: unknown;
29
+ try {
30
+ parsed = JSON.parse(text);
31
+ } catch {
32
+ return [...fallback];
33
+ }
34
+ return parseRouteTable(parsed) ?? [...fallback];
35
+ }
@@ -0,0 +1,42 @@
1
+ import type { AppResource } from 'cheminfo-mcp-server';
2
+
3
+ import type { AnswerAddressesInput } from './answerAddresses.ts';
4
+ import { viewOrigins } from './answerAddresses.ts';
5
+ import { mcpServer } from './mcpServer.ts';
6
+
7
+ /** What {@link siteView} names, and where its pages come from. */
8
+ export interface SiteViewOptions {
9
+ /** Its address, which the tools name in `ui.resourceUri`: `ui://lcao/page`. */
10
+ uri: string;
11
+ /** For people: the site's host, `lcao.cheminfo.org`. */
12
+ name: string;
13
+ /** For people: what the card shows inline, and the page over the screen. */
14
+ description: string;
15
+ /** Where the site and this server are: the view frames both, and no other. */
16
+ addresses: AnswerAddressesInput;
17
+ /**
18
+ * The height of the frame, in pixels, for a page that cannot report its
19
+ * own.
20
+ * @default undefined - the page reports its height, as `CardFrame` does
21
+ */
22
+ height?: number;
23
+ }
24
+
25
+ /**
26
+ * The MCP App showing an answer on the site's own page: inline the answer's
27
+ * card, the page itself over the full screen, framed from this server or from
28
+ * the static site. One per tool server, named by every tool whose answer
29
+ * carries a `meta` from `cardMeta` or `pageAnswer`.
30
+ * @param options - Its address, its name, and the two addresses it frames.
31
+ * @returns The resource, for `createToolRoutes({ resources })`.
32
+ */
33
+ export function siteView(options: SiteViewOptions): AppResource {
34
+ const { uri, name, description, addresses, height } = options;
35
+ return mcpServer().embedView({
36
+ uri,
37
+ name,
38
+ description,
39
+ origins: viewOrigins(addresses),
40
+ height,
41
+ });
42
+ }
@@ -0,0 +1,179 @@
1
+ import { withoutQueryOrFragment } from '../router/core/address.ts';
2
+ import { stripBasePath } from '../router/core/basePath.ts';
3
+ import { noscriptIndex } from '../seo/core/noscript.ts';
4
+ import { pageHeadTags } from '../seo/core/pageMeta.ts';
5
+ import type { PageContent } from '../seo/core/pageProse.ts';
6
+ import type { RouteMeta } from '../seo/core/routes.ts';
7
+ import { pageMetaFor, routeFor } from '../seo/core/routes.ts';
8
+ import { mountPathOf, resolveSite } from '../seo/core/siteFiles.ts';
9
+ import { structuredDataScript } from '../seo/core/structuredData.ts';
10
+ import {
11
+ PAGE_BODY_MARKER,
12
+ PAGE_HEAD_MARKER,
13
+ fill,
14
+ } from '../seo/core/template.ts';
15
+ import { injectTrackingScript } from '../seo/core/trackingScript.ts';
16
+
17
+ import type { SpaSiteOptions } from './spaSiteOptions.ts';
18
+
19
+ /** The page an address is answered with. */
20
+ export interface SpaAnswer {
21
+ /** The page, its head and its crawl path written for the address. */
22
+ html: string;
23
+ /** Whether the app routes the address, rather than drawing its "not found". */
24
+ known: boolean;
25
+ }
26
+
27
+ /** Writes the page every address of a single-page app is answered with. */
28
+ export interface SpaPages {
29
+ /**
30
+ * The page for one address.
31
+ * @param url - The address asked for, query string included.
32
+ * @param origin - Where the site is served, mount path included.
33
+ * @returns The page, and whether the app routes the address.
34
+ */
35
+ answer: (url: string, origin: string) => Promise<SpaAnswer>;
36
+ }
37
+
38
+ /**
39
+ * Prepare the pages of a single-page app from its built template: the snippet
40
+ * is put in once, the crawl path is written once per page and kept, and the
41
+ * head — which names the origin the request arrived on — per request.
42
+ * @param template - The built `index.html`.
43
+ * @param routes - Every address the app routes itself.
44
+ * @param options - The site, and how its pages are written.
45
+ * @returns The page writer.
46
+ * @throws {Error} When an indexed site's template carries no head or body
47
+ * marker, rather than failing on every request afterwards.
48
+ */
49
+ export function createSpaPages(
50
+ template: string,
51
+ routes: readonly RouteMeta[],
52
+ options: SpaSiteOptions,
53
+ ): SpaPages {
54
+ const site = resolveSite(options.site);
55
+ const indexed = options.indexed ?? true;
56
+ const page = injectTrackingScript(template, options.trackingScript);
57
+ if (indexed) {
58
+ for (const marker of [PAGE_HEAD_MARKER, PAGE_BODY_MARKER]) {
59
+ if (!page.includes(marker)) {
60
+ throw new Error(`the page carries no ${marker}`);
61
+ }
62
+ }
63
+ }
64
+ const write = indexed ? fill : fillIfPresent;
65
+ const bodyFor = keptBodies(options.maxCachedPages ?? 2000);
66
+ const crawled = options.noscript?.routes ?? indexedRoutes(routes);
67
+ const structured = structuredData(routes, options);
68
+
69
+ return {
70
+ async answer(url, origin) {
71
+ const mount = mountPathOf({ site, origin });
72
+ const named = await options.page?.(url);
73
+ const meta = named?.meta ?? pageMetaFor(routes, url, mount);
74
+ const content: PageContent = named?.content ?? {
75
+ heading: meta.title,
76
+ paragraphs: [meta.description],
77
+ };
78
+ const body = bodyFor(
79
+ meta.path,
80
+ `${mount}\n${JSON.stringify(content)}`,
81
+ () =>
82
+ write(
83
+ page,
84
+ PAGE_BODY_MARKER,
85
+ noscriptIndex({
86
+ ...options.noscript,
87
+ site,
88
+ origin,
89
+ routes: crawled,
90
+ content,
91
+ }),
92
+ ),
93
+ );
94
+ const served = indexed ? meta : { ...meta, indexed: false };
95
+ const tags = pageHeadTags({
96
+ site,
97
+ routes: [served],
98
+ origin,
99
+ url: served.path,
100
+ image: options.image,
101
+ });
102
+ const script = indexed ? structured(origin) : undefined;
103
+ const head = script === undefined ? tags : `${tags}\n${script}`;
104
+ return {
105
+ html: write(body, PAGE_HEAD_MARKER, head),
106
+ known:
107
+ named !== undefined ||
108
+ isKnown(routes, url, mount, options.knownRoute),
109
+ };
110
+ },
111
+ };
112
+ }
113
+
114
+ function indexedRoutes(routes: readonly RouteMeta[]): RouteMeta[] {
115
+ return routes.filter((route) => route.indexed !== false);
116
+ }
117
+
118
+ function isKnown(
119
+ routes: readonly RouteMeta[],
120
+ url: string,
121
+ mount: string,
122
+ knownRoute: ((path: string) => boolean) | undefined,
123
+ ): boolean {
124
+ const path = withoutQueryOrFragment(url);
125
+ const own = stripBasePath(mount, path);
126
+ if (knownRoute !== undefined) return knownRoute(own);
127
+ return (
128
+ routeFor(routes, own) !== undefined || routeFor(routes, path) !== undefined
129
+ );
130
+ }
131
+
132
+ // The block is the same on every page of an origin, so the one origin a
133
+ // configured site is served at is written once rather than per request.
134
+ function structuredData(
135
+ routes: readonly RouteMeta[],
136
+ options: SpaSiteOptions,
137
+ ): (origin: string) => string | undefined {
138
+ const option = options.structuredData ?? {};
139
+ if (option === false) return () => undefined;
140
+ if (typeof option === 'function') return option;
141
+ let last: { origin: string; script: string } | undefined;
142
+ return (origin) => {
143
+ if (last?.origin !== origin) {
144
+ const script = structuredDataScript({
145
+ ...option,
146
+ site: options.site,
147
+ routes,
148
+ origin,
149
+ });
150
+ last = { origin, script };
151
+ }
152
+ return last.script;
153
+ };
154
+ }
155
+
156
+ // The crawl path of a page is kept under its canonical path, and rebuilt when
157
+ // what the page says changes — a course renamed, a compound read again.
158
+ function keptBodies(
159
+ limit: number,
160
+ ): (path: string, key: string, build: () => string) => string {
161
+ const kept = new Map<string, { key: string; html: string }>();
162
+ return (path, key, build) => {
163
+ const entry = kept.get(path);
164
+ if (entry?.key === key) return entry.html;
165
+ const html = build();
166
+ if (limit <= 0) return html;
167
+ kept.delete(path);
168
+ if (kept.size >= limit) {
169
+ const oldest = kept.keys().next();
170
+ if (oldest.done !== true) kept.delete(oldest.value);
171
+ }
172
+ kept.set(path, { key, html });
173
+ return html;
174
+ };
175
+ }
176
+
177
+ function fillIfPresent(html: string, marker: string, content: string): string {
178
+ return html.includes(marker) ? fill(html, marker, content) : html;
179
+ }
@@ -0,0 +1,216 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join, relative, resolve, sep } from 'node:path';
3
+
4
+ import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
5
+
6
+ import type { SiteRecord } from '../ecosystem/core/sites.ts';
7
+ import { robotsTxt } from '../seo/core/robots.ts';
8
+ import type { RouteMeta } from '../seo/core/routes.ts';
9
+ import { originOf, resolveSite, sitemapXml } from '../seo/core/siteFiles.ts';
10
+
11
+ import { healthRoute } from './healthRoute.ts';
12
+ import {
13
+ BUNDLE_CACHE,
14
+ DEFAULT_RESERVED,
15
+ HIDDEN,
16
+ PAGE_CACHE,
17
+ } from './routeOptions.ts';
18
+ import { readRouteTable } from './routeTable.ts';
19
+ import { isHashedBundle, listSiteFiles } from './siteFiles.ts';
20
+ import type { SpaPages } from './spaPages.ts';
21
+ import { createSpaPages } from './spaPages.ts';
22
+ import type { SpaSiteOptions } from './spaSiteOptions.ts';
23
+
24
+ /** The page the build wrote, which is a template and never served as it is. */
25
+ const INDEX = 'index.html';
26
+
27
+ /** What keeps a page out of the index without stopping its crawl. */
28
+ const NO_INDEX = 'noindex, nofollow';
29
+
30
+ /** The policy of a site nobody is meant to find. */
31
+ const DISALLOW_ALL = 'User-agent: *\nDisallow: /\n';
32
+
33
+ /**
34
+ * Serve a single-page app from the backend that answers its API.
35
+ *
36
+ * Every address the app routes itself is the built page, with the head of that
37
+ * address — its title, description, canonical and card — and a crawl path of
38
+ * its own in its body, so a crawler that runs no script still tells the pages
39
+ * apart. The `TRACKING_SCRIPT` snippet is in every page. `sitemap.xml` and
40
+ * `robots.txt` are written from the route table, at the address the site is
41
+ * served at; the files of the build are served as they are, `assets/` kept for
42
+ * a year; an address under `reserved` is the API's own 404; and `/health`
43
+ * answers the deploy script.
44
+ *
45
+ * await app.register(spaSite, {
46
+ * root: 'frontend/dist',
47
+ * site: 'derepflow',
48
+ * siteUrl: process.env.SITE_URL,
49
+ * trackingScript: process.env.TRACKING_SCRIPT,
50
+ * });
51
+ *
52
+ * Without a build — a server started before the frontend was built — it logs
53
+ * it and serves the API alone.
54
+ * @param fastify - The server.
55
+ * @param options - The build, the site, and how its pages are written.
56
+ * @throws {Error} When `siteUrl` is not an absolute address, or the page of an
57
+ * indexed site carries no `<!--cheminfo:head-->` or `<!--cheminfo:body-->`.
58
+ */
59
+ export async function spaSite(
60
+ fastify: FastifyInstance,
61
+ options: SpaSiteOptions,
62
+ ): Promise<void> {
63
+ const {
64
+ health = true,
65
+ reserved = DEFAULT_RESERVED,
66
+ notFoundStatus = 200,
67
+ indexed = true,
68
+ siteUrl,
69
+ robots = DEFAULT_RESERVED,
70
+ sitemapPaths,
71
+ setHeaders,
72
+ } = options;
73
+ const site = resolveSite(options.site);
74
+ if (health !== false) {
75
+ await healthRoute(fastify, health === true ? {} : health);
76
+ }
77
+
78
+ const root = resolve(options.root);
79
+ const files = await listSiteFiles(root);
80
+ if (!files?.has(INDEX)) {
81
+ fastify.log.warn({ root }, 'no built frontend: serving the API alone');
82
+ return;
83
+ }
84
+ const routes = options.routes ?? readRouteTable(root, [homeOf(site)]);
85
+ const configured = siteUrl?.trim() || undefined;
86
+ if (configured !== undefined) originOf({ site, origin: configured });
87
+ const pages = createSpaPages(
88
+ await readFile(join(root, INDEX), 'utf8'),
89
+ routes,
90
+ options,
91
+ );
92
+ const originFor = (request: FastifyRequest) =>
93
+ configured ?? requestOrigin(request, site);
94
+
95
+ // An optional peer, installed only by a site that has a server: importing
96
+ // react-cheminfo/server must not need it.
97
+ const { default: fastifyStatic } = await import('@fastify/static');
98
+ await fastify.register(fastifyStatic, {
99
+ root,
100
+ serve: false,
101
+ cacheControl: false,
102
+ setHeaders: (reply, path) => {
103
+ const file = relative(root, path).split(sep).join('/');
104
+ reply.header(
105
+ 'cache-control',
106
+ isHashedBundle(file) ? BUNDLE_CACHE : PAGE_CACHE,
107
+ );
108
+ if (!indexed) reply.header('x-robots-tag', NO_INDEX);
109
+ setHeaders?.(reply, file);
110
+ },
111
+ });
112
+
113
+ const sendPage = sender(pages, originFor, { indexed, notFoundStatus });
114
+ const answer = (request: FastifyRequest, reply: FastifyReply) => {
115
+ const { pathname, search } = new URL(request.url, 'http://site');
116
+ if (reserved.some((prefix) => pathname.startsWith(prefix))) {
117
+ return reply.callNotFound();
118
+ }
119
+ if (pathname === `/${INDEX}`) return sendPage(request, reply, `/${search}`);
120
+ const file = buildFile(files, pathname);
121
+ if (file !== undefined) return reply.sendFile(file);
122
+ return sendPage(request, reply, request.url);
123
+ };
124
+ fastify.get('/', { schema: HIDDEN }, answer);
125
+ fastify.get('/*', { schema: HIDDEN }, answer);
126
+
127
+ fastify.get('/robots.txt', { schema: HIDDEN }, (request, reply) =>
128
+ reply
129
+ .type('text/plain; charset=utf-8')
130
+ .send(
131
+ indexed
132
+ ? robotsTxt({ site, routes, origin: originFor(request) }, robots)
133
+ : DISALLOW_ALL,
134
+ ),
135
+ );
136
+ fastify.get('/sitemap.xml', { schema: HIDDEN }, async (request, reply) => {
137
+ if (!indexed) return reply.callNotFound();
138
+ const paths = (await sitemapPaths?.()) ?? [];
139
+ const listed: RouteMeta[] = [...routes];
140
+ for (const path of paths) listed.push({ path, title: '', description: '' });
141
+ return reply
142
+ .type('application/xml; charset=utf-8')
143
+ .send(sitemapXml({ site, routes: listed, origin: originFor(request) }));
144
+ });
145
+ }
146
+
147
+ /**
148
+ * The handler answering an address with its page.
149
+ * @param pages - The page writer.
150
+ * @param originFor - Where the site is served, for a request.
151
+ * @param status - How the answer is labelled.
152
+ * @param status.indexed - Whether search engines may index the site.
153
+ * @param status.notFoundStatus - The status of an address the app does not route.
154
+ * @returns The handler.
155
+ */
156
+ function sender(
157
+ pages: SpaPages,
158
+ originFor: (request: FastifyRequest) => string,
159
+ status: { indexed: boolean; notFoundStatus: number },
160
+ ) {
161
+ return async (request: FastifyRequest, reply: FastifyReply, url: string) => {
162
+ const { html, known } = await pages.answer(url, originFor(request));
163
+ reply.header('cache-control', PAGE_CACHE);
164
+ if (!status.indexed) reply.header('x-robots-tag', NO_INDEX);
165
+ return reply
166
+ .code(known ? 200 : status.notFoundStatus)
167
+ .type('text/html; charset=utf-8')
168
+ .send(html);
169
+ };
170
+ }
171
+
172
+ /**
173
+ * The file of the build an address names, never the template.
174
+ * @param files - The files of the build.
175
+ * @param pathname - The address, without its query.
176
+ * @returns The file, or `undefined` when the address is a page.
177
+ */
178
+ function buildFile(
179
+ files: ReadonlySet<string>,
180
+ pathname: string,
181
+ ): string | undefined {
182
+ let path: string;
183
+ try {
184
+ path = decodeURIComponent(pathname);
185
+ } catch {
186
+ return undefined;
187
+ }
188
+ const local = path.replace(/^\/+/, '');
189
+ if (local === '' || local === INDEX) return undefined;
190
+ return files.has(local) ? local : undefined;
191
+ }
192
+
193
+ /**
194
+ * The origin a request arrived on. The `Host` header is the client's to write,
195
+ * so one that is not a host falls back to the site's own address rather than
196
+ * reaching a canonical link.
197
+ * @param request - The request.
198
+ * @param site - The site served.
199
+ * @returns The origin, e.g. `https://pdb.cheminfo.org`.
200
+ */
201
+ function requestOrigin(request: FastifyRequest, site: SiteRecord): string {
202
+ const candidate = `${request.protocol}://${request.host}`;
203
+ return URL.canParse(candidate)
204
+ ? new URL(candidate).origin
205
+ : `https://${site.host}`;
206
+ }
207
+
208
+ /**
209
+ * The page a site answers when its build wrote no route table.
210
+ * @param site - The site.
211
+ * @returns Its home page, titled and described by its tagline.
212
+ */
213
+ function homeOf(site: SiteRecord): RouteMeta {
214
+ const title = site.tagline.replace(/\.$/, '');
215
+ return { path: '/', title, description: site.tagline };
216
+ }