@l1yp/file-viewer 0.1.1 → 0.1.3

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 (440) hide show
  1. package/README.md +1 -0
  2. package/dist/FileViewer.js +2 -0
  3. package/dist/FileViewer.js.map +1 -0
  4. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  5. package/dist/FileViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  6. package/dist/components/AppxViewer.js +2 -0
  7. package/dist/components/AppxViewer.js.map +1 -0
  8. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  9. package/dist/components/AppxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  10. package/dist/components/ArchiveBrowser.js +2 -0
  11. package/dist/components/ArchiveBrowser.js.map +1 -0
  12. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  13. package/dist/components/ArchiveBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  14. package/dist/components/AudioViewer.js +2 -0
  15. package/dist/components/AudioViewer.js.map +1 -0
  16. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  17. package/dist/components/AudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  18. package/dist/components/BinObjBrowser.js +2 -0
  19. package/dist/components/BinObjBrowser.js.map +1 -0
  20. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  21. package/dist/components/BinObjBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  22. package/dist/components/CertViewer.js +2 -0
  23. package/dist/components/CertViewer.js.map +1 -0
  24. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  25. package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  26. package/dist/components/ClassViewer.js +2 -0
  27. package/dist/components/ClassViewer.js.map +1 -0
  28. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  29. package/dist/components/ClassViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  30. package/dist/components/CodeBlock.js +2 -0
  31. package/dist/components/CodeBlock.js.map +1 -0
  32. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  33. package/dist/components/CodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  34. package/dist/components/CodeView.js +2 -0
  35. package/dist/components/CodeView.js.map +1 -0
  36. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js +2 -0
  37. package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  38. package/dist/components/CsvViewer.js +2 -0
  39. package/dist/components/CsvViewer.js.map +1 -0
  40. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  41. package/dist/components/CsvViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  42. package/dist/components/DicomViewer.js +2 -0
  43. package/dist/components/DicomViewer.js.map +1 -0
  44. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  45. package/dist/components/DicomViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  46. package/dist/components/DocxNavigationPane.js +2 -0
  47. package/dist/components/DocxNavigationPane.js.map +1 -0
  48. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js +2 -0
  49. package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  50. package/dist/components/DocxViewer.js +2 -0
  51. package/dist/components/DocxViewer.js.map +1 -0
  52. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  53. package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  54. package/dist/components/DrawioViewer.js +2 -0
  55. package/dist/components/DrawioViewer.js.map +1 -0
  56. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  57. package/dist/components/DrawioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  58. package/dist/components/DxfViewer.js +2 -0
  59. package/dist/components/DxfViewer.js.map +1 -0
  60. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  61. package/dist/components/DxfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  62. package/dist/components/EbookViewer.js +2 -0
  63. package/dist/components/EbookViewer.js.map +1 -0
  64. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  65. package/dist/components/EbookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  66. package/dist/components/EmlViewer.js +2 -0
  67. package/dist/components/EmlViewer.js.map +1 -0
  68. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  69. package/dist/components/EmlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  70. package/dist/components/EplViewer.js +2 -0
  71. package/dist/components/EplViewer.js.map +1 -0
  72. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  73. package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  74. package/dist/components/FileViewerBody.js +3 -1
  75. package/dist/components/FileViewerBody.js.map +1 -0
  76. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js +2 -0
  77. package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js.map +1 -0
  78. package/dist/components/FileViewerPanel.js +2 -0
  79. package/dist/components/FileViewerPanel.js.map +1 -0
  80. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js +2 -0
  81. package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  82. package/dist/components/FontViewer.js +2 -0
  83. package/dist/components/FontViewer.js.map +1 -0
  84. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  85. package/dist/components/FontViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  86. package/dist/components/FrontmatterCard.js +2 -0
  87. package/dist/components/FrontmatterCard.js.map +1 -0
  88. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js +2 -0
  89. package/dist/components/FrontmatterCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  90. package/dist/components/GeoViewer.js +2 -0
  91. package/dist/components/GeoViewer.js.map +1 -0
  92. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  93. package/dist/components/GeoViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  94. package/dist/components/HarViewer.js +2 -0
  95. package/dist/components/HarViewer.js.map +1 -0
  96. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  97. package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  98. package/dist/components/HexViewer.js +2 -0
  99. package/dist/components/HexViewer.js.map +1 -0
  100. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  101. package/dist/components/HexViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  102. package/dist/components/HprofViewer.js +2 -0
  103. package/dist/components/HprofViewer.js.map +1 -0
  104. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  105. package/dist/components/HprofViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  106. package/dist/components/ImageLightbox.js +2 -0
  107. package/dist/components/ImageLightbox.js.map +1 -0
  108. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js +2 -0
  109. package/dist/components/ImageLightbox.vue_vue_type_script_setup_true_lang.js.map +1 -0
  110. package/dist/components/InlineText.js +2 -0
  111. package/dist/components/InlineText.js.map +1 -0
  112. package/dist/components/JksViewer.js +2 -0
  113. package/dist/components/JksViewer.js.map +1 -0
  114. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  115. package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  116. package/dist/components/JsonlViewer.js +3 -1
  117. package/dist/components/JsonlViewer.js.map +1 -0
  118. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  119. package/dist/components/JsonlViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  120. package/dist/components/LogViewer.js +2 -0
  121. package/dist/components/LogViewer.js.map +1 -0
  122. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  123. package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  124. package/dist/components/LrcViewer.js +2 -0
  125. package/dist/components/LrcViewer.js.map +1 -0
  126. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  127. package/dist/components/LrcViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  128. package/dist/components/MarkdownTable.js +2 -0
  129. package/dist/components/MarkdownTable.js.map +1 -0
  130. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js +2 -0
  131. package/dist/components/MarkdownTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  132. package/dist/components/MarkdownText.js +2 -0
  133. package/dist/components/MarkdownText.js.map +1 -0
  134. package/dist/components/MhtViewer.js +2 -0
  135. package/dist/components/MhtViewer.js.map +1 -0
  136. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  137. package/dist/components/MhtViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  138. package/dist/components/MindMapView.js +2 -0
  139. package/dist/components/MindMapView.js.map +1 -0
  140. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js +2 -0
  141. package/dist/components/MindMapView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  142. package/dist/components/MissingDependency.js +2 -0
  143. package/dist/components/MissingDependency.js.map +1 -0
  144. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js +2 -0
  145. package/dist/components/MissingDependency.vue_vue_type_script_setup_true_lang.js.map +1 -0
  146. package/dist/components/ModelViewer.js +2 -0
  147. package/dist/components/ModelViewer.js.map +1 -0
  148. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  149. package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  150. package/dist/components/MsiViewer.js +2 -0
  151. package/dist/components/MsiViewer.js.map +1 -0
  152. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  153. package/dist/components/MsiViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  154. package/dist/components/NotebookViewer.js +2 -0
  155. package/dist/components/NotebookViewer.js.map +1 -0
  156. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  157. package/dist/components/NotebookViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  158. package/dist/components/PdfNavigationPane.js +9 -0
  159. package/dist/components/PdfNavigationPane.js.map +1 -0
  160. package/dist/components/PdfNavigationPane.vue.d.ts +24 -0
  161. package/dist/components/PdfNavigationPane.vue_vue_type_script_setup_true_lang.js +149 -0
  162. package/dist/components/PdfNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  163. package/dist/components/PdfViewer.js +3 -1
  164. package/dist/components/PdfViewer.js.map +1 -0
  165. package/dist/components/PdfViewer.vue.d.ts +0 -11
  166. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js +133 -69
  167. package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  168. package/dist/components/PptxNavigationPane.js +2 -0
  169. package/dist/components/PptxNavigationPane.js.map +1 -0
  170. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js +2 -0
  171. package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -0
  172. package/dist/components/PptxViewer.js +3 -1
  173. package/dist/components/PptxViewer.js.map +1 -0
  174. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js +55 -49
  175. package/dist/components/PptxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  176. package/dist/components/PsdViewer.js +2 -0
  177. package/dist/components/PsdViewer.js.map +1 -0
  178. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  179. package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  180. package/dist/components/QmcAudioViewer.js +2 -0
  181. package/dist/components/QmcAudioViewer.js.map +1 -0
  182. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  183. package/dist/components/QmcAudioViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  184. package/dist/components/RasterViewer.js +2 -0
  185. package/dist/components/RasterViewer.js.map +1 -0
  186. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  187. package/dist/components/RasterViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  188. package/dist/components/RtfViewer.js +2 -0
  189. package/dist/components/RtfViewer.js.map +1 -0
  190. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  191. package/dist/components/RtfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  192. package/dist/components/SevenZipBrowser.js +2 -0
  193. package/dist/components/SevenZipBrowser.js.map +1 -0
  194. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  195. package/dist/components/SevenZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  196. package/dist/components/SqliteViewer.js +2 -0
  197. package/dist/components/SqliteViewer.js.map +1 -0
  198. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  199. package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  200. package/dist/components/SubtitleViewer.js +2 -0
  201. package/dist/components/SubtitleViewer.js.map +1 -0
  202. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  203. package/dist/components/SubtitleViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  204. package/dist/components/XlsxChart.js +2 -0
  205. package/dist/components/XlsxChart.js.map +1 -0
  206. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js +2 -0
  207. package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  208. package/dist/components/XlsxViewer.js +2 -0
  209. package/dist/components/XlsxViewer.js.map +1 -0
  210. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  211. package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  212. package/dist/components/XmindViewer.js +2 -0
  213. package/dist/components/XmindViewer.js.map +1 -0
  214. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js +2 -0
  215. package/dist/components/XmindViewer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  216. package/dist/components/ZipBrowser.js +2 -0
  217. package/dist/components/ZipBrowser.js.map +1 -0
  218. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js +2 -0
  219. package/dist/components/ZipBrowser.vue_vue_type_script_setup_true_lang.js.map +1 -0
  220. package/dist/components/ZoomImage.js +3 -1
  221. package/dist/components/ZoomImage.js.map +1 -0
  222. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js +82 -80
  223. package/dist/components/ZoomImage.vue_vue_type_script_setup_true_lang.js.map +1 -0
  224. package/dist/components/epl/EplCodeBlock.js +2 -0
  225. package/dist/components/epl/EplCodeBlock.js.map +1 -0
  226. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js +2 -0
  227. package/dist/components/epl/EplCodeBlock.vue_vue_type_script_setup_true_lang.js.map +1 -0
  228. package/dist/components/epl/EplDoc.js +2 -0
  229. package/dist/components/epl/EplDoc.js.map +1 -0
  230. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js +2 -0
  231. package/dist/components/epl/EplDoc.vue_vue_type_script_setup_true_lang.js.map +1 -0
  232. package/dist/components/epl/EplMethod.js +2 -0
  233. package/dist/components/epl/EplMethod.js.map +1 -0
  234. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js +2 -0
  235. package/dist/components/epl/EplMethod.vue_vue_type_script_setup_true_lang.js.map +1 -0
  236. package/dist/components/epl/EplResource.js +2 -0
  237. package/dist/components/epl/EplResource.js.map +1 -0
  238. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js +2 -0
  239. package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js.map +1 -0
  240. package/dist/components/epl/EplTree.js +2 -0
  241. package/dist/components/epl/EplTree.js.map +1 -0
  242. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js +2 -0
  243. package/dist/components/epl/EplTree.vue_vue_type_script_setup_true_lang.js.map +1 -0
  244. package/dist/components/epl/EplVarTable.js +2 -0
  245. package/dist/components/epl/EplVarTable.js.map +1 -0
  246. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js +2 -0
  247. package/dist/components/epl/EplVarTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  248. package/dist/components/epl/numbering.js +2 -0
  249. package/dist/components/epl/numbering.js.map +1 -0
  250. package/dist/components/icons/Icon.js +2 -0
  251. package/dist/components/icons/Icon.js.map +1 -0
  252. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js +2 -0
  253. package/dist/components/icons/Icon.vue_vue_type_script_setup_true_lang.js.map +1 -0
  254. package/dist/components/icons/iconPaths.js +2 -0
  255. package/dist/components/icons/iconPaths.js.map +1 -0
  256. package/dist/components/optionalViewer.js +2 -0
  257. package/dist/components/optionalViewer.js.map +1 -0
  258. package/dist/components/ui/ClampBlock.js +2 -0
  259. package/dist/components/ui/ClampBlock.js.map +1 -0
  260. package/dist/composables/useElementNavigation.js +2 -0
  261. package/dist/composables/useElementNavigation.js.map +1 -0
  262. package/dist/composables/useFileViewer.js +2 -0
  263. package/dist/composables/useFileViewer.js.map +1 -0
  264. package/dist/composables/useLightbox.js +2 -0
  265. package/dist/composables/useLightbox.js.map +1 -0
  266. package/dist/composables/useLogRules.js +2 -0
  267. package/dist/composables/useLogRules.js.map +1 -0
  268. package/dist/lib/aes.js +2 -0
  269. package/dist/lib/aes.js.map +1 -0
  270. package/dist/lib/appx.js +2 -0
  271. package/dist/lib/appx.js.map +1 -0
  272. package/dist/lib/archiveHtml.js +2 -0
  273. package/dist/lib/archiveHtml.js.map +1 -0
  274. package/dist/lib/asn1.js +2 -0
  275. package/dist/lib/asn1.js.map +1 -0
  276. package/dist/lib/binobj.js +2 -0
  277. package/dist/lib/binobj.js.map +1 -0
  278. package/dist/lib/brotli.js +2 -0
  279. package/dist/lib/brotli.js.map +1 -0
  280. package/dist/lib/bzip2.js +2 -0
  281. package/dist/lib/bzip2.js.map +1 -0
  282. package/dist/lib/classfile.js +2 -0
  283. package/dist/lib/classfile.js.map +1 -0
  284. package/dist/lib/codePreview.js +2 -0
  285. package/dist/lib/codePreview.js.map +1 -0
  286. package/dist/lib/codefold.js +2 -0
  287. package/dist/lib/codefold.js.map +1 -0
  288. package/dist/lib/codeformat.js +2 -0
  289. package/dist/lib/codeformat.js.map +1 -0
  290. package/dist/lib/csv.js +2 -0
  291. package/dist/lib/csv.js.map +1 -0
  292. package/dist/lib/des.js +2 -0
  293. package/dist/lib/des.js.map +1 -0
  294. package/dist/lib/diagram.js +2 -0
  295. package/dist/lib/diagram.js.map +1 -0
  296. package/dist/lib/dicom.js +2 -0
  297. package/dist/lib/dicom.js.map +1 -0
  298. package/dist/lib/dicomCodecs.js +2 -0
  299. package/dist/lib/dicomCodecs.js.map +1 -0
  300. package/dist/lib/dicomRender.js +2 -0
  301. package/dist/lib/dicomRender.js.map +1 -0
  302. package/dist/lib/docxNavigation.js +2 -0
  303. package/dist/lib/docxNavigation.js.map +1 -0
  304. package/dist/lib/dxf.js +2 -0
  305. package/dist/lib/dxf.js.map +1 -0
  306. package/dist/lib/eml.js +2 -0
  307. package/dist/lib/eml.js.map +1 -0
  308. package/dist/lib/encoding.js +2 -0
  309. package/dist/lib/encoding.js.map +1 -0
  310. package/dist/lib/epl/code/codeDataParser.js +2 -0
  311. package/dist/lib/epl/code/codeDataParser.js.map +1 -0
  312. package/dist/lib/epl/code/codeLines.js +2 -0
  313. package/dist/lib/epl/code/codeLines.js.map +1 -0
  314. package/dist/lib/epl/code/textCode.js +2 -0
  315. package/dist/lib/epl/code/textCode.js.map +1 -0
  316. package/dist/lib/epl/eplDocument.js +2 -0
  317. package/dist/lib/epl/eplDocument.js.map +1 -0
  318. package/dist/lib/epl/imageList.js +2 -0
  319. package/dist/lib/epl/imageList.js.map +1 -0
  320. package/dist/lib/epl/index.js +2 -0
  321. package/dist/lib/epl/index.js.map +1 -0
  322. package/dist/lib/epl/io/binaryReader.js +2 -0
  323. package/dist/lib/epl/io/binaryReader.js.map +1 -0
  324. package/dist/lib/epl/io/encoding.js +2 -0
  325. package/dist/lib/epl/io/encoding.js.map +1 -0
  326. package/dist/lib/epl/model/eplSystemId.js +2 -0
  327. package/dist/lib/epl/model/eplSystemId.js.map +1 -0
  328. package/dist/lib/epl/names/eplLibData.js +2 -0
  329. package/dist/lib/epl/names/eplLibData.js.map +1 -0
  330. package/dist/lib/epl/names/idToNameMap.js +2 -0
  331. package/dist/lib/epl/names/idToNameMap.js.map +1 -0
  332. package/dist/lib/epl/names/libNameProvider.js +2 -0
  333. package/dist/lib/epl/names/libNameProvider.js.map +1 -0
  334. package/dist/lib/epl/program.js +2 -0
  335. package/dist/lib/epl/program.js.map +1 -0
  336. package/dist/lib/epl/projectFileReader.js +2 -0
  337. package/dist/lib/epl/projectFileReader.js.map +1 -0
  338. package/dist/lib/fb2.js +2 -0
  339. package/dist/lib/fb2.js.map +1 -0
  340. package/dist/lib/fileType.js +2 -0
  341. package/dist/lib/fileType.js.map +1 -0
  342. package/dist/lib/fonts.js +2 -0
  343. package/dist/lib/fonts.js.map +1 -0
  344. package/dist/lib/format.js +2 -0
  345. package/dist/lib/format.js.map +1 -0
  346. package/dist/lib/frontmatter.js +2 -0
  347. package/dist/lib/frontmatter.js.map +1 -0
  348. package/dist/lib/geo.js +2 -0
  349. package/dist/lib/geo.js.map +1 -0
  350. package/dist/lib/har.js +2 -0
  351. package/dist/lib/har.js.map +1 -0
  352. package/dist/lib/highlight.js +2 -0
  353. package/dist/lib/highlight.js.map +1 -0
  354. package/dist/lib/highlightLangs.js +2 -0
  355. package/dist/lib/highlightLangs.js.map +1 -0
  356. package/dist/lib/hprof.js +2 -0
  357. package/dist/lib/hprof.js.map +1 -0
  358. package/dist/lib/ipynb.js +2 -0
  359. package/dist/lib/ipynb.js.map +1 -0
  360. package/dist/lib/jks.js +2 -0
  361. package/dist/lib/jks.js.map +1 -0
  362. package/dist/lib/jsonl.js +2 -0
  363. package/dist/lib/jsonl.js.map +1 -0
  364. package/dist/lib/lrc.js +2 -0
  365. package/dist/lib/lrc.js.map +1 -0
  366. package/dist/lib/lzma.js +2 -0
  367. package/dist/lib/lzma.js.map +1 -0
  368. package/dist/lib/markdown/blocks.js +2 -0
  369. package/dist/lib/markdown/blocks.js.map +1 -0
  370. package/dist/lib/markdown/inline.js +2 -0
  371. package/dist/lib/markdown/inline.js.map +1 -0
  372. package/dist/lib/markdown/math.js +2 -0
  373. package/dist/lib/markdown/math.js.map +1 -0
  374. package/dist/lib/markdown/segmentize.js +2 -0
  375. package/dist/lib/markdown/segmentize.js.map +1 -0
  376. package/dist/lib/markdown/styles.js +2 -0
  377. package/dist/lib/markdown/styles.js.map +1 -0
  378. package/dist/lib/mht.js +2 -0
  379. package/dist/lib/mht.js.map +1 -0
  380. package/dist/lib/midi.js +2 -0
  381. package/dist/lib/midi.js.map +1 -0
  382. package/dist/lib/mime.js +2 -0
  383. package/dist/lib/mime.js.map +1 -0
  384. package/dist/lib/mindmap.js +2 -0
  385. package/dist/lib/mindmap.js.map +1 -0
  386. package/dist/lib/mobi.js +2 -0
  387. package/dist/lib/mobi.js.map +1 -0
  388. package/dist/lib/msi.js +2 -0
  389. package/dist/lib/msi.js.map +1 -0
  390. package/dist/lib/optionalDep.js +2 -0
  391. package/dist/lib/optionalDep.js.map +1 -0
  392. package/dist/lib/pdfNavigation.d.ts +11 -0
  393. package/dist/lib/pdfNavigation.js +32 -0
  394. package/dist/lib/pdfNavigation.js.map +1 -0
  395. package/dist/lib/pkcs12.js +2 -0
  396. package/dist/lib/pkcs12.js.map +1 -0
  397. package/dist/lib/pptxNavigation.js +2 -0
  398. package/dist/lib/pptxNavigation.js.map +1 -0
  399. package/dist/lib/qmc.js +2 -0
  400. package/dist/lib/qmc.js.map +1 -0
  401. package/dist/lib/rar.js +2 -0
  402. package/dist/lib/rar.js.map +1 -0
  403. package/dist/lib/rawPreview.js +2 -0
  404. package/dist/lib/rawPreview.js.map +1 -0
  405. package/dist/lib/rc2.js +2 -0
  406. package/dist/lib/rc2.js.map +1 -0
  407. package/dist/lib/resolveInput.js +2 -0
  408. package/dist/lib/resolveInput.js.map +1 -0
  409. package/dist/lib/rtf.js +2 -0
  410. package/dist/lib/rtf.js.map +1 -0
  411. package/dist/lib/sevenZip.js +2 -0
  412. package/dist/lib/sevenZip.js.map +1 -0
  413. package/dist/lib/sha1.js +2 -0
  414. package/dist/lib/sha1.js.map +1 -0
  415. package/dist/lib/sha256.js +2 -0
  416. package/dist/lib/sha256.js.map +1 -0
  417. package/dist/lib/speechAudio.js +2 -0
  418. package/dist/lib/speechAudio.js.map +1 -0
  419. package/dist/lib/sqlite.js +2 -0
  420. package/dist/lib/sqlite.js.map +1 -0
  421. package/dist/lib/subtitle.js +2 -0
  422. package/dist/lib/subtitle.js.map +1 -0
  423. package/dist/lib/tarball.js +2 -0
  424. package/dist/lib/tarball.js.map +1 -0
  425. package/dist/lib/viewerFormats.js +2 -0
  426. package/dist/lib/viewerFormats.js.map +1 -0
  427. package/dist/lib/viewerKind.js +2 -0
  428. package/dist/lib/viewerKind.js.map +1 -0
  429. package/dist/lib/x509.js +2 -0
  430. package/dist/lib/x509.js.map +1 -0
  431. package/dist/lib/xlsx.js +2 -0
  432. package/dist/lib/xlsx.js.map +1 -0
  433. package/dist/lib/xlsxCharts.js +2 -0
  434. package/dist/lib/xlsxCharts.js.map +1 -0
  435. package/dist/lib/xmind.js +2 -0
  436. package/dist/lib/xmind.js.map +1 -0
  437. package/dist/lib/zip.js +2 -0
  438. package/dist/lib/zip.js.map +1 -0
  439. package/dist/style.css +1 -1
  440. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocks.js","names":[],"sources":["../../../src/lib/markdown/blocks.ts"],"sourcesContent":["import { h, type VNode } from 'vue'\nimport CodeBlock from '@/components/CodeBlock.vue'\nimport MarkdownTable from '@/components/MarkdownTable.vue'\nimport { inline } from './inline'\nimport { blockMath } from './math'\nimport {\n blockquoteStyle,\n headingStyle,\n hrStyle,\n listItemStyle,\n listStyle,\n paragraphStyle,\n taskCheckboxStyle,\n} from './styles'\n\n/** Convenience: render a fenced code block VNode. */\nfunction codeBlock(\n code: string,\n lang: string,\n key: string,\n opts?: { maxHeight?: string; margin?: string },\n): VNode {\n return h(CodeBlock, { key, code, lang, maxHeight: opts?.maxHeight, margin: opts?.margin })\n}\n\n/** Convenience: render a GFM table VNode. */\nfunction tableBlock(\n header: string[],\n aligns: (string | null)[],\n rows: string[][],\n key: string,\n): VNode {\n return h(MarkdownTable, { key, header, aligns, rows, keyPrefix: key })\n}\n\n/**\n * Block-level markdown → VNodes. Handles fenced code, ATX headings (## / ###),\n * GFM pipe tables, ordered/unordered lists (with nesting + fenced code inside\n * items), and paragraphs with hard line breaks. Faithful port of `mdNodes`.\n */\nexport function mdNodes(text: string, kp: string, depth: number): VNode[] {\n const lines = String(text).replace(/\\t/g, ' ').split('\\n')\n const out: VNode[] = []\n const pStyle = paragraphStyle(depth)\n let i = 0\n let bk = 0\n\n const indOf = (l: string) => l.match(/^(\\s*)/)![1].length\n\n // A thematic break: a whole line of 3+ of the same -, *, or _ (spaces allowed between).\n const isHr = (l: string) => /^ {0,3}([-*_])(?:[ \\t]*\\1){2,}[ \\t]*$/.test(l)\n\n // A GFM table delimiter row: contains a pipe and every cell is :?-+:?\n const isTableSep = (l: string): boolean => {\n if (l.indexOf('|') === -1) return false\n let s = l.trim()\n if (s.charAt(0) === '|') s = s.slice(1)\n if (s.charAt(s.length - 1) === '|') s = s.slice(0, -1)\n const cells = s.split('|')\n return cells.length > 0 && cells.every((c) => /^\\s*:?-+:?\\s*$/.test(c))\n }\n\n // Split one table row into trimmed cells, honoring `\\|` escapes and edge pipes.\n const splitRow = (l: string): string[] => {\n let s = l.trim()\n if (s.charAt(0) === '|') s = s.slice(1)\n if (s.charAt(s.length - 1) === '|') s = s.slice(0, -1)\n const cells: string[] = []\n let cur = ''\n for (let ci = 0; ci < s.length; ci++) {\n const ch = s.charAt(ci)\n if (ch === '\\\\' && s.charAt(ci + 1) === '|') {\n cur += '|'\n ci++\n continue\n }\n if (ch === '|') {\n cells.push(cur.trim())\n cur = ''\n continue\n }\n cur += ch\n }\n cells.push(cur.trim())\n return cells\n }\n\n while (i < lines.length) {\n const line = lines[i]\n if (line.trim() === '') {\n i++\n continue\n }\n const key = `${kp}-${bk++}`\n\n // fenced code (allowed at any indent — used inside list items)\n const fence = line.match(/^(\\s*)```+\\s*([^`]*)$/)\n if (fence) {\n const pad = fence[1].length\n const lang = fence[2]\n const body: string[] = []\n i++\n while (i < lines.length && !/^\\s*```+\\s*$/.test(lines[i])) {\n body.push(lines[i].slice(pad))\n i++\n }\n i++ // consume closing fence\n out.push(codeBlock(body.join('\\n'), lang, key))\n continue\n }\n\n // display math: `$$ … $$` or `\\[ … \\]` on its own line (may span multiple lines). Hand the TeX\n // to KaTeX (blockMath) — the hand-rolled engine doesn't typeset math. Detected here so the `$`/`\\`\n // internals never reach the paragraph/inline rules that would mangle them.\n const dmOpen = line.match(/^\\s*(\\$\\$|\\\\\\[)/)\n if (dmOpen) {\n const open = dmOpen[1]\n const close = open === '$$' ? '$$' : '\\\\]'\n const head = line.slice(line.indexOf(open) + open.length)\n const sameLineEnd = head.indexOf(close)\n let tex: string\n if (sameLineEnd !== -1) {\n tex = head.slice(0, sameLineEnd) // single line: $$ … $$\n i++\n } else {\n const buf = [head]\n i++\n while (i < lines.length) {\n const end = lines[i].indexOf(close)\n if (end !== -1) {\n buf.push(lines[i].slice(0, end))\n i++\n break\n }\n buf.push(lines[i])\n i++\n }\n tex = buf.join('\\n')\n }\n out.push(blockMath(tex.trim(), key))\n continue\n }\n\n // thematic break (--- / *** / ___) — before lists, since `* * *` looks like a bullet\n if (isHr(line)) {\n out.push(h('hr', { key, style: hrStyle }))\n i++\n continue\n }\n\n // blockquote (> …): gather the quoted lines, strip one `>` level, recurse (supports nesting)\n if (/^\\s*>/.test(line)) {\n const buf: string[] = []\n while (i < lines.length) {\n if (/^\\s*>/.test(lines[i])) {\n buf.push(lines[i].replace(/^\\s*>\\s?/, ''))\n i++\n } else if (lines[i].trim() === '') {\n // a blank line continues the quote only if another `>` line follows\n let j = i + 1\n while (j < lines.length && lines[j].trim() === '') j++\n if (j < lines.length && /^\\s*>/.test(lines[j])) {\n buf.push('')\n i = j\n continue\n }\n break\n } else break\n }\n out.push(\n h('blockquote', { key, style: blockquoteStyle }, mdNodes(buf.join('\\n'), key, depth)),\n )\n continue\n }\n\n // heading (# … ######)\n const hd = line.match(/^(#{1,6})\\s+(.*)$/)\n if (hd) {\n const lvl = hd[1].length\n const st = headingStyle(lvl, out.length === 0)\n out.push(h(`h${lvl}`, { key, style: st }, inline(hd[2], key)))\n i++\n continue\n }\n\n // table (GFM pipe table): header row immediately followed by a delimiter row\n if (line.indexOf('|') !== -1 && i + 1 < lines.length && isTableSep(lines[i + 1])) {\n const header = splitRow(line)\n const aligns = splitRow(lines[i + 1]).map((c) => {\n const L = c.charAt(0) === ':'\n const R = c.charAt(c.length - 1) === ':'\n return L && R ? 'center' : R ? 'right' : L ? 'left' : null\n })\n i += 2\n const rows: string[][] = []\n while (i < lines.length) {\n const r = lines[i]\n if (r.trim() === '' || r.indexOf('|') === -1 || /^\\s*```+/.test(r) || /^#{1,6}\\s/.test(r))\n break\n rows.push(splitRow(r))\n i++\n }\n out.push(tableBlock(header, aligns, rows, key))\n continue\n }\n\n // ordered / unordered list\n const om = line.match(/^(\\s*)(\\d+)\\.\\s+/)\n const um = line.match(/^(\\s*)([-*+•])\\s+/)\n if (om || um) {\n const ordered = !!om\n const baseIndent = (om || um)![1].length\n const markerRe = ordered ? /^(\\s*)(\\d+)\\.\\s+([\\s\\S]*)$/ : /^(\\s*)([-*+•])\\s+([\\s\\S]*)$/\n const items: string[][] = []\n let startNum: number | null = null\n while (i < lines.length) {\n const mm = lines[i].match(markerRe)\n // `* * *` / `- - -` match the bullet shape but are thematic breaks — let them end the list.\n if (mm && mm[1].length === baseIndent && !isHr(lines[i])) {\n if (ordered && startNum === null) startNum = parseInt(mm[2], 10)\n const itemLines = [mm[3]]\n i++\n while (i < lines.length) {\n if (lines[i].trim() === '') {\n itemLines.push('')\n i++\n continue\n }\n const ind = indOf(lines[i])\n const sm = lines[i].match(markerRe)\n if (ind > baseIndent && !(sm && sm[1].length === baseIndent)) {\n itemLines.push(lines[i])\n i++\n } else break\n }\n items.push(itemLines)\n } else if (lines[i].trim() === '') {\n // blank line: continue list only if a same-level item or indented child follows\n let j = i + 1\n while (j < lines.length && lines[j].trim() === '') j++\n if (j < lines.length) {\n const pk = lines[j].match(markerRe)\n if (\n (pk && pk[1].length === baseIndent && !isHr(lines[j])) ||\n indOf(lines[j]) > baseIndent\n ) {\n i = j\n continue\n }\n }\n break\n } else break\n }\n const lStyle = listStyle(depth, ordered)\n const liStyle = listItemStyle(depth)\n const children = items.map((raw, idx) => {\n let minInd = Infinity\n raw.slice(1).forEach((l) => {\n if (l.trim() !== '') minInd = Math.min(minInd, indOf(l))\n })\n if (!isFinite(minInd)) minInd = 0\n const dedented = [raw[0]].concat(\n raw.slice(1).map((l) => (l.trim() === '' ? '' : l.slice(minInd))),\n )\n const content = dedented.join('\\n').replace(/\\n+$/, '')\n // GFM task item: a leading `[ ]` / `[x]` turns the bullet into a checkbox\n const task = ordered ? null : /^\\[([ xX])\\]\\s+/.exec(content)\n const checked = !!task && task[1].toLowerCase() === 'x'\n const body = task ? content.slice(task[0].length) : content\n const innerNodes = mdNodes(body, `${key}-i${idx}`, depth + 1)\n // unwrap a lone paragraph so list markers hug their text\n const onlyP = innerNodes.length === 1 && innerNodes[0] && innerNodes[0].type === 'p'\n if (task) {\n const box = h(\n 'span',\n { key: 'cb', style: taskCheckboxStyle(checked), 'aria-hidden': 'true' },\n checked ? '✓' : '',\n )\n const inner = onlyP\n ? [box, ...((innerNodes[0].children as VNode[]) || [])]\n : [box, ...innerNodes]\n return h('li', { key: idx, style: { ...liStyle, listStyleType: 'none' } }, inner)\n }\n const kids = onlyP\n ? h(\n 'span',\n {\n style: {\n display: 'block',\n fontFamily: liStyle.fontFamily,\n fontSize: liStyle.fontSize,\n lineHeight: 1.72,\n },\n },\n innerNodes[0].children as VNode[],\n )\n : innerNodes\n return h('li', { key: idx, style: liStyle }, kids)\n })\n const olAttr = ordered && startNum && startNum !== 1 ? { start: startNum } : {}\n out.push(h(ordered ? 'ol' : 'ul', { key, style: lStyle, ...olAttr }, children))\n continue\n }\n\n // paragraph: gather until a blank line or a block-starting line\n const para = [line]\n i++\n while (i < lines.length) {\n const l = lines[i]\n if (l.trim() === '') break\n if (\n /^\\s*```+/.test(l) ||\n /^\\s*(\\$\\$|\\\\\\[)/.test(l) ||\n /^#{1,6}\\s/.test(l) ||\n /^\\s*>/.test(l) ||\n isHr(l) ||\n /^\\s*\\d+\\.\\s+/.test(l) ||\n /^\\s*[-*+•]\\s+/.test(l)\n )\n break\n if (l.indexOf('|') !== -1 && i + 1 < lines.length && isTableSep(lines[i + 1])) break\n para.push(l)\n i++\n }\n const nodes: (VNode | string)[] = []\n para.forEach((l, li) => {\n if (li > 0) nodes.push(h('br', { key: `br${li}` }))\n inline(l, `${key}-l${li}`).forEach((n) => nodes.push(n))\n })\n out.push(h('p', { key, style: pStyle }, nodes))\n }\n return out\n}\n\n/** Top-level markdown entry (depth 0). */\nexport function md(text: string, kp: string): VNode[] {\n return mdNodes(text, kp, 0)\n}\n"],"mappings":"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"}
@@ -82,3 +82,5 @@ function p(d, p) {
82
82
  }
83
83
  //#endregion
84
84
  export { p as inline, d as renderInline };
85
+
86
+ //# sourceMappingURL=inline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline.js","names":[],"sources":["../../../src/lib/markdown/inline.ts"],"sourcesContent":["import { h, type VNode } from 'vue'\nimport { useLightbox } from '@/composables/useLightbox'\nimport { inlineMath } from './math'\nimport { delStyle, emStyle, imgStyle, inlineCodeStyle, linkStyle, strongStyle } from './styles'\n\nexport type InlineNode = VNode | string\n\n/**\n * Resolve an inline citation token to its rendered chip(s), or null to strip it. Provider-specific (ChatGPT\n * supplies one via {@link renderInline}); the shared renderer just calls it for citation tokens it finds.\n */\nexport type CiteResolver = (token: string) => InlineNode[] | null\n\n/**\n * Resolve a markdown link to custom inline nodes, or null to render a normal anchor. Lets a provider turn\n * specific links into rich nodes — ChatGPT renders managed file-download links as file chips (preview/download)\n * via {@link renderInline}; everything else falls through to a plain `<a>`.\n */\nexport type LinkResolver = (text: string, href: string) => InlineNode[] | null\n\n// Active during a synchronous render pass only — set by renderInline around a (synchronous) md()/inline() call,\n// restored after. No await happens between set and restore, so this is safe under SSR (single-threaded, no\n// interleaving). Both default to null (Claude installs neither): citation tokens are then stripped and links\n// render as plain anchors.\nlet activeCite: CiteResolver | null = null\nlet activeLink: LinkResolver | null = null\n\n/** Inline resolvers a provider can install for one render pass. */\nexport interface InlineResolvers {\n cite?: CiteResolver\n link?: LinkResolver\n}\n\n/** Run [body] with the given inline [resolvers] active, restoring the previous ones afterwards. */\nexport function renderInline<T>(resolvers: InlineResolvers, body: () => T): T {\n const prevCite = activeCite\n const prevLink = activeLink\n activeCite = resolvers.cite ?? null\n activeLink = resolvers.link ?? null\n try {\n return body()\n } finally {\n activeCite = prevCite\n activeLink = prevLink\n }\n}\n\n// ChatGPT wraps inline-citation tokens in Private Use Area delimiters (U+E200…U+E201, separator U+E202) and uses\n// other PUA marks (e.g. U+E203 for hidden refs). Strip any stray ones from plain text so no garbage leaks through.\nconst PUA_RE = /[\\u{e200}-\\u{e20f}]/gu\n\n/**\n * Render inline markdown to an array of VNodes/strings.\n * Order matters: code first (nothing is parsed inside it), then math (`$…$` / `\\(…\\)`, pulled out\n * before emphasis so TeX internals like `_` `*` `\\` aren't mangled), image before link\n * (`![…](…)` contains `[…](…)`), bold (`**`/`__`) before italic (`*`/`_`).\n * Groups: 1 code, 2 math-`$`, 3 math-`\\(`, 4 img-alt, 5 img-url, 6 bold, 7 underscore-bold,\n * 8 strike, 9 link-text, 10 link-url, 11 italic, 12 underscore-italic, 13 citation (PUA-delimited),\n * 14 citation (`【n†…】`). The opening `$` is guarded against a following space/`$` and the closing\n * against a following word char, so prose prices like `$5` don't trigger math. Underscore emphasis is\n * guarded by alnum boundaries so `snake_case` stays intact.\n * Citation tokens resolve via the active {@link CiteResolver} (or are stripped when none is set).\n */\nexport function inline(s: string, kp: string): InlineNode[] {\n const parts: InlineNode[] = []\n // Push a plain-text run, stripping any stray citation PUA marks; skip if nothing is left.\n const pushText = (t: string): void => {\n const c = t.replace(PUA_RE, '')\n if (c) parts.push(c)\n }\n // Fresh regex per call so lastIndex never leaks between invocations.\n const re =\n /`([^`\\n]+?)`|\\$(?![ \\t$])((?:\\\\.|[^$\\n\\\\])+?)\\$(?![\\w$])|\\\\\\(([\\s\\S]+?)\\\\\\)|!\\[([^\\]\\n]*?)\\]\\(([^)\\s]+?)\\)|\\*\\*([\\s\\S]+?)\\*\\*|__([^_]+?)__|~~([\\s\\S]+?)~~|\\[([^\\]\\n]+?)\\]\\(([^)\\s]+?)\\)|\\*([^\\s*][^*]*?)\\*|(?<![A-Za-z0-9_])_([^_]+?)_(?![A-Za-z0-9_])|(\\u{e200}[\\s\\S]*?\\u{e201})|(【[^】\\n]*?†[^】\\n]*?】)/gu\n let last = 0\n let m: RegExpExecArray | null\n let k = 0\n while ((m = re.exec(s))) {\n if (m.index > last) pushText(s.slice(last, m.index))\n if (m[1] !== undefined) {\n parts.push(h('code', { key: `${kp}-c${k++}`, style: inlineCodeStyle }, m[1]))\n } else if (m[2] !== undefined) {\n parts.push(inlineMath(m[2], `${kp}-m${k++}`))\n } else if (m[3] !== undefined) {\n parts.push(inlineMath(m[3], `${kp}-m${k++}`))\n } else if (m[4] !== undefined) {\n const src = m[5]\n const alt = m[4]\n parts.push(\n h('img', {\n key: `${kp}-img${k++}`,\n src,\n alt,\n loading: 'lazy',\n style: { ...imgStyle, cursor: 'zoom-in' },\n // Click any inline image to enlarge it in the shared lightbox (same overlay as image thumbnails).\n onClick: () => useLightbox().open({ src, alt }),\n }),\n )\n } else if (m[6] !== undefined) {\n parts.push(h('strong', { key: `${kp}-s${k++}`, style: strongStyle }, m[6]))\n } else if (m[7] !== undefined) {\n parts.push(h('strong', { key: `${kp}-s${k++}`, style: strongStyle }, m[7]))\n } else if (m[8] !== undefined) {\n parts.push(h('del', { key: `${kp}-d${k++}`, style: delStyle }, m[8]))\n } else if (m[9] !== undefined) {\n const href = m[10] ?? ''\n const custom = activeLink ? activeLink(m[9], href) : null\n if (custom) {\n for (const n of custom) parts.push(n)\n } else {\n parts.push(\n h(\n 'a',\n {\n key: `${kp}-a${k++}`,\n href,\n target: '_blank',\n rel: 'noopener noreferrer',\n style: linkStyle,\n },\n m[9],\n ),\n )\n }\n } else if (m[11] !== undefined) {\n parts.push(h('em', { key: `${kp}-e${k++}`, style: emStyle }, m[11]))\n } else if (m[12] !== undefined) {\n parts.push(h('em', { key: `${kp}-e${k++}`, style: emStyle }, m[12]))\n } else {\n // citation token (m[13] PUA-delimited, or m[14] 【n†…】) — render via the active resolver, else strip\n const token = m[13] ?? m[14] ?? ''\n const rendered = activeCite ? activeCite(token) : null\n if (rendered) for (const n of rendered) parts.push(n)\n }\n last = re.lastIndex\n }\n if (last < s.length) pushText(s.slice(last))\n return parts\n}\n"],"mappings":"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"}
@@ -23,3 +23,5 @@ function i(t, r) {
23
23
  }
24
24
  //#endregion
25
25
  export { i as blockMath, r as inlineMath };
26
+
27
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","names":[],"sources":["../../../src/lib/markdown/math.ts"],"sourcesContent":["import katex from 'katex'\nimport { h, type VNode } from 'vue'\n\n/**\n * TeX math → VNode, rendered by KaTeX. The hand-rolled markdown engine deliberately doesn't\n * typeset math (that's a full TeX layout problem, a different league from markdown) — so this is\n * the one place it delegates to a library, exactly like `highlight.js` for code.\n *\n * Why KaTeX fits this codebase:\n * - `renderToString` is *synchronous*, so it slots into the existing synchronous VNode pipeline\n * and the SSR smoke (`pnpm smoke`) with no async plumbing.\n * - It ships its own woff2 math fonts, bundled and self-hosted (no CDN) — see the css imports in\n * `main.ts` (`katex/dist/katex.min.css`) and the overrides in `assets/styles/katex.css`.\n * - `throwOnError: false` makes an invalid formula render as red source text instead of throwing\n * and blanking the message.\n *\n * The HTML KaTeX emits is its own trusted output, so feeding it through `innerHTML` is safe (same\n * pattern as WidgetBlock's static SVG). Never pass raw user text here — only KaTeX's result.\n */\nfunction render(tex: string, displayMode: boolean): string {\n return katex.renderToString(tex, { displayMode, throwOnError: false })\n}\n\n/** Inline formula (`$…$` / `\\(…\\)`) — flows within the surrounding line. */\nexport function inlineMath(tex: string, key: string): VNode {\n return h('span', { key, class: 'math-inline', innerHTML: render(tex, false) })\n}\n\n/** Display formula (`$$…$$` / `\\[…\\]`) — its own centered block, scrolls sideways if too wide. */\nexport function blockMath(tex: string, key: string): VNode {\n return h('div', { key, class: 'math-block', innerHTML: render(tex, true) })\n}\n"],"mappings":";;;AAmBA,SAAS,EAAO,GAAa,GAA8B;CACzD,OAAO,EAAM,eAAe,GAAK;EAAE;EAAa,cAAc;CAAM,CAAC;AACvE;AAGA,SAAgB,EAAW,GAAa,GAAoB;CAC1D,OAAO,EAAE,QAAQ;EAAE;EAAK,OAAO;EAAe,WAAW,EAAO,GAAK,EAAK;CAAE,CAAC;AAC/E;AAGA,SAAgB,EAAU,GAAa,GAAoB;CACzD,OAAO,EAAE,OAAO;EAAE;EAAK,OAAO;EAAc,WAAW,EAAO,GAAK,EAAI;CAAE,CAAC;AAC5E"}
@@ -26,3 +26,5 @@ function e(e) {
26
26
  }
27
27
  //#endregion
28
28
  export { e as segmentize };
29
+
30
+ //# sourceMappingURL=segmentize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmentize.js","names":[],"sources":["../../../src/lib/markdown/segmentize.ts"],"sourcesContent":["export interface Segment {\n code: boolean\n text: string\n lang?: string\n}\n\n/**\n * Split markdown into ordered segments of prose and fenced code blocks.\n * Blank lines inside fences are preserved; blank lines around prose are trimmed.\n * Faithful port of the original `segmentize` (used for human messages).\n */\nexport function segmentize(text: string): Segment[] {\n const lines = String(text).split('\\n')\n const segs: Segment[] = []\n let buf: string[] = []\n let i = 0\n const flush = () => {\n if (buf.length) {\n const t = buf.join('\\n').replace(/^\\n+/, '').replace(/\\n+$/, '')\n if (t.trim()) segs.push({ code: false, text: t })\n buf = []\n }\n }\n while (i < lines.length) {\n const fence = lines[i].match(/^\\s*```+\\s*([^`]*)$/)\n if (fence) {\n flush()\n const lang = fence[1]\n const body: string[] = []\n i++\n while (i < lines.length && !/^\\s*```+\\s*$/.test(lines[i])) {\n body.push(lines[i])\n i++\n }\n i++ // consume closing fence\n segs.push({ code: true, lang, text: body.join('\\n') })\n } else {\n buf.push(lines[i])\n i++\n }\n }\n flush()\n return segs\n}\n"],"mappings":";AAWA,SAAgB,EAAW,GAAyB;CAClD,IAAM,IAAQ,OAAO,CAAI,CAAC,CAAC,MAAM,IAAI,GAC/B,IAAkB,CAAC,GACrB,IAAgB,CAAC,GACjB,IAAI,GACF,UAAc;EAClB,IAAI,EAAI,QAAQ;GACd,IAAM,IAAI,EAAI,KAAK,IAAI,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE;GAE/D,AADI,EAAE,KAAK,KAAG,EAAK,KAAK;IAAE,MAAM;IAAO,MAAM;GAAE,CAAC,GAChD,IAAM,CAAC;EACT;CACF;CACA,OAAO,IAAI,EAAM,SAAQ;EACvB,IAAM,IAAQ,EAAM,EAAE,CAAC,MAAM,qBAAqB;EAClD,IAAI,GAAO;GACT,EAAM;GACN,IAAM,IAAO,EAAM,IACb,IAAiB,CAAC;GAExB,KADA,KACO,IAAI,EAAM,UAAU,CAAC,eAAe,KAAK,EAAM,EAAE,IAEtD,AADA,EAAK,KAAK,EAAM,EAAE,GAClB;GAGF,AADA,KACA,EAAK,KAAK;IAAE,MAAM;IAAM;IAAM,MAAM,EAAK,KAAK,IAAI;GAAE,CAAC;EACvD,OAEE,AADA,EAAI,KAAK,EAAM,EAAE,GACjB;CAEJ;CAEA,OADA,EAAM,GACC;AACT"}
@@ -133,3 +133,5 @@ function m(e) {
133
133
  }
134
134
  //#endregion
135
135
  export { p as blockquoteStyle, c as delStyle, l as emStyle, r as headingStyle, f as hrStyle, d as imgStyle, o as inlineCodeStyle, u as linkStyle, a as listItemStyle, i as listStyle, n as paragraphStyle, s as strongStyle, m as taskCheckboxStyle };
136
+
137
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","names":[],"sources":["../../../src/lib/markdown/styles.ts"],"sourcesContent":["import type { CSSProperties } from 'vue'\nimport { MONO, SERIF } from '@/lib/fonts'\n\n/**\n * Centralized typography for markdown-rendered nodes. The render functions build\n * raw VNodes (outside any SFC), so they can't use scoped CSS — keeping every\n * markdown style in this one file is the maintainable equivalent: tweak prose\n * sizing/spacing here and it applies everywhere markdown is rendered.\n *\n * `depth` mirrors the original: 0 = top level, >0 = nested inside a list item.\n */\n\nexport function paragraphStyle(depth: number): CSSProperties {\n return depth > 0\n ? {\n fontFamily: SERIF,\n fontSize: '16.5px',\n lineHeight: 1.7,\n margin: '0 0 8px',\n color: 'var(--text)',\n }\n : {\n fontFamily: SERIF,\n fontSize: '17px',\n lineHeight: 1.78,\n margin: '0 0 16px',\n color: 'var(--text)',\n }\n}\n\nexport function headingStyle(level: number, first: boolean): CSSProperties {\n const base: CSSProperties = { fontFamily: SERIF, fontWeight: 600, color: 'var(--text-strong)' }\n switch (level) {\n case 1:\n return {\n ...base,\n fontSize: '24px',\n margin: `${first ? '4px' : '32px'} 0 15px`,\n letterSpacing: '-0.02em',\n lineHeight: 1.3,\n }\n case 2:\n return {\n ...base,\n fontSize: '20px',\n margin: `${first ? '4px' : '30px'} 0 13px`,\n letterSpacing: '-0.01em',\n lineHeight: 1.35,\n }\n case 3:\n return { ...base, fontSize: '17px', margin: '22px 0 9px', lineHeight: 1.4 }\n case 4:\n return { ...base, fontSize: '15.5px', margin: '20px 0 8px', lineHeight: 1.45 }\n case 5:\n return { ...base, fontSize: '14px', margin: '18px 0 6px', lineHeight: 1.5 }\n default: // h6\n return {\n ...base,\n fontSize: '13px',\n margin: '18px 0 6px',\n letterSpacing: '0.01em',\n color: 'var(--muted)',\n lineHeight: 1.5,\n }\n }\n}\n\nexport function listStyle(depth: number, ordered: boolean): CSSProperties {\n return {\n margin: depth > 0 ? '8px 0 10px' : '4px 0 18px',\n paddingLeft: ordered ? '28px' : '24px',\n }\n}\n\nexport function listItemStyle(depth: number): CSSProperties {\n return {\n fontFamily: SERIF,\n fontSize: depth > 0 ? '16.5px' : '17px',\n lineHeight: 1.72,\n color: 'var(--text)',\n margin: '0 0 7px',\n paddingLeft: '3px',\n }\n}\n\nexport const inlineCodeStyle: CSSProperties = {\n fontFamily: MONO,\n fontSize: '0.86em',\n background: 'var(--code-bg)',\n border: '1px solid var(--code-border)',\n borderRadius: '5px',\n padding: '1.5px 5px',\n color: 'var(--accent)',\n overflowWrap: 'anywhere',\n}\n\nexport const strongStyle: CSSProperties = { fontWeight: 600, color: 'var(--text-strong)' }\nexport const delStyle: CSSProperties = { color: 'var(--muted)' }\nexport const emStyle: CSSProperties = { fontStyle: 'italic' }\nexport const linkStyle: CSSProperties = {\n color: 'var(--accent)',\n textDecoration: 'underline',\n textUnderlineOffset: '2px',\n textDecorationThickness: '1px',\n}\n\n/** Inline image (`![alt](url)`). Scales down to the column, never overflows. */\nexport const imgStyle: CSSProperties = {\n maxWidth: '100%',\n height: 'auto',\n borderRadius: '8px',\n margin: '6px 0',\n border: '1px solid var(--border)',\n}\n\n/** Thematic break (`---` / `***` / `___`). */\nexport const hrStyle: CSSProperties = {\n border: 'none',\n borderTop: '1px solid var(--border)',\n margin: '28px 0',\n}\n\n/** Blockquote (`> …`): left rule + softened text; nests via recursion. */\nexport const blockquoteStyle: CSSProperties = {\n margin: '0 0 16px',\n padding: '2px 0 2px 16px',\n borderLeft: '3px solid var(--border-2)',\n color: 'var(--muted)',\n}\n\n/** GFM task-list checkbox (`- [ ]` / `- [x]`) — a styled box, not a native input, for theme control. */\nexport function taskCheckboxStyle(checked: boolean): CSSProperties {\n return {\n display: 'inline-block',\n width: '15px',\n height: '15px',\n boxSizing: 'border-box',\n verticalAlign: '-2px',\n marginRight: '8px',\n borderRadius: '4px',\n border: `1.5px solid ${checked ? 'var(--accent)' : 'var(--border-2)'}`,\n background: checked ? 'var(--accent)' : 'transparent',\n color: '#fff',\n fontSize: '11px',\n lineHeight: '12px',\n textAlign: 'center',\n fontWeight: 700,\n }\n}\n"],"mappings":";;AAYA,SAAgB,EAAe,GAA8B;CAC3D,OAAO,IAAQ,IACX;EACE,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,QAAQ;EACR,OAAO;CACT,IACA;EACE,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,QAAQ;EACR,OAAO;CACT;AACN;AAEA,SAAgB,EAAa,GAAe,GAA+B;CACzE,IAAM,IAAsB;EAAE,YAAY;EAAO,YAAY;EAAK,OAAO;CAAqB;CAC9F,QAAQ,GAAR;EACE,KAAK,GACH,OAAO;GACL,GAAG;GACH,UAAU;GACV,QAAQ,GAAG,IAAQ,QAAQ,OAAO;GAClC,eAAe;GACf,YAAY;EACd;EACF,KAAK,GACH,OAAO;GACL,GAAG;GACH,UAAU;GACV,QAAQ,GAAG,IAAQ,QAAQ,OAAO;GAClC,eAAe;GACf,YAAY;EACd;EACF,KAAK,GACH,OAAO;GAAE,GAAG;GAAM,UAAU;GAAQ,QAAQ;GAAc,YAAY;EAAI;EAC5E,KAAK,GACH,OAAO;GAAE,GAAG;GAAM,UAAU;GAAU,QAAQ;GAAc,YAAY;EAAK;EAC/E,KAAK,GACH,OAAO;GAAE,GAAG;GAAM,UAAU;GAAQ,QAAQ;GAAc,YAAY;EAAI;EAC5E,SACE,OAAO;GACL,GAAG;GACH,UAAU;GACV,QAAQ;GACR,eAAe;GACf,OAAO;GACP,YAAY;EACd;CACJ;AACF;AAEA,SAAgB,EAAU,GAAe,GAAiC;CACxE,OAAO;EACL,QAAQ,IAAQ,IAAI,eAAe;EACnC,aAAa,IAAU,SAAS;CAClC;AACF;AAEA,SAAgB,EAAc,GAA8B;CAC1D,OAAO;EACL,YAAY;EACZ,UAAU,IAAQ,IAAI,WAAW;EACjC,YAAY;EACZ,OAAO;EACP,QAAQ;EACR,aAAa;CACf;AACF;AAEA,IAAa,IAAiC;CAC5C,YAAY;CACZ,UAAU;CACV,YAAY;CACZ,QAAQ;CACR,cAAc;CACd,SAAS;CACT,OAAO;CACP,cAAc;AAChB,GAEa,IAA6B;CAAE,YAAY;CAAK,OAAO;AAAqB,GAC5E,IAA0B,EAAE,OAAO,eAAe,GAClD,IAAyB,EAAE,WAAW,SAAS,GAC/C,IAA2B;CACtC,OAAO;CACP,gBAAgB;CAChB,qBAAqB;CACrB,yBAAyB;AAC3B,GAGa,IAA0B;CACrC,UAAU;CACV,QAAQ;CACR,cAAc;CACd,QAAQ;CACR,QAAQ;AACV,GAGa,IAAyB;CACpC,QAAQ;CACR,WAAW;CACX,QAAQ;AACV,GAGa,IAAiC;CAC5C,QAAQ;CACR,SAAS;CACT,YAAY;CACZ,OAAO;AACT;AAGA,SAAgB,EAAkB,GAAiC;CACjE,OAAO;EACL,SAAS;EACT,OAAO;EACP,QAAQ;EACR,WAAW;EACX,eAAe;EACf,aAAa;EACb,cAAc;EACd,QAAQ,eAAe,IAAU,kBAAkB;EACnD,YAAY,IAAU,kBAAkB;EACxC,OAAO;EACP,UAAU;EACV,YAAY;EACZ,WAAW;EACX,YAAY;CACd;AACF"}
package/dist/lib/mht.js CHANGED
@@ -120,3 +120,5 @@ function p(e, t) {
120
120
  }
121
121
  //#endregion
122
122
  export { d as parseMht, p as rewriteHtml };
123
+
124
+ //# sourceMappingURL=mht.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mht.js","names":[],"sources":["../../src/lib/mht.ts"],"sourcesContent":["/**\n * Hand-rolled MHT / MHTML (web archive, RFC 2557) parser — the archive-specific layer on top of the shared\n * MIME core (lib/mime.ts). An `.mht`/`.mhtml` is a `multipart/related` MIME container: a root HTML part plus\n * the page's resources (images / CSS / fonts), each part referenced from the HTML by its original URL via a\n * `Content-Location` header (vs. an email's `cid:` Content-ID).\n *\n * Two halves:\n * - {@link parseMht} (pure, unit-testable): parse the container, pick the root HTML part, and index every\n * other part by its absolute Content-Location (and Content-ID, for the rare `cid:` archive).\n * - {@link rewriteHtml} (browser-only, uses DOMParser): rewrite the HTML's resource references to caller-\n * supplied blob URLs, strip scripts, and inject a hardened CSP — so the archive renders offline inside a\n * sandboxed iframe without running upstream script or phoning home. See MhtViewer.vue.\n */\n\nimport {\n bytesToBinary,\n collectLeaves,\n decodeCharset,\n decodeWords,\n getHeader,\n parseEntity,\n parseHeaders,\n splitHeadersBody,\n type Entity,\n} from '@/lib/mime'\n\n/** A single archived page resource (image / stylesheet / font / …). */\nexport interface MhtResource {\n contentType: string\n /** Charset label from the part's Content-Type (for text resources like CSS); '' when none. */\n charset: string\n bytes: Uint8Array\n}\n\n/** Flattened, render-ready view of a parsed web archive. */\nexport interface ParsedMht {\n /** `Subject:` header — the saved page's title (browsers write the document title here). */\n title: string\n /** Original page URL (`Snapshot-Content-Location` or the root `Content-Location`), for display. */\n sourceUrl: string\n /** Raw `Date:` header value (the viewer formats it for display). */\n date: string\n /** Decoded root HTML (NOT yet resource-rewritten), or null when the archive has no HTML part. */\n html: string | null\n /** Base URL for resolving the root HTML's resource references (the root part's Content-Location). */\n rootBase: string\n /** Absolute Content-Location → resource. */\n byLocation: Map<string, MhtResource>\n /** Content-ID (no angle brackets) → resource. */\n byCid: Map<string, MhtResource>\n}\n\n/** The hardened CSP injected into the archive before it's handed to the sandboxed iframe. */\nexport const MHT_CSP =\n \"default-src 'none'; img-src blob: data:; media-src blob: data:; \" +\n \"style-src blob: data: 'unsafe-inline'; font-src blob: data:; \" +\n \"script-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'\"\n\n/** Resolve `ref` against `base` to an absolute URL; returns `ref` unchanged when it can't be resolved. */\nfunction absolutize(ref: string, base: string): string {\n try {\n return new URL(ref, base || undefined).href\n } catch {\n return ref\n }\n}\n\n/** Strip surrounding angle brackets from a Content-ID / `start` reference. */\nfunction unwrapId(id: string): string {\n return id.trim().replace(/^<|>$/g, '')\n}\n\n/** Parse raw `.mht`/`.mhtml` bytes into a flattened {@link ParsedMht}. */\nexport function parseMht(bytes: Uint8Array): ParsedMht {\n const bin = bytesToBinary(bytes)\n const root = parseEntity(bin)\n const headers = parseHeaders(splitHeadersBody(bin)[0])\n\n const leaves: Entity[] = []\n collectLeaves(root, leaves)\n\n // Pick the root HTML part: the multipart/related `start` (a Content-ID), else the first text/html leaf.\n const start = unwrapId(root.ctParams.start || '')\n let rootHtmlLeaf: Entity | undefined\n if (start) rootHtmlLeaf = leaves.find((l) => l.contentId === start)\n if (!rootHtmlLeaf) rootHtmlLeaf = leaves.find((l) => l.contentType === 'text/html')\n\n // Every other leaf is a page resource, keyed by its (absolute) Content-Location and/or Content-ID.\n const byLocation = new Map<string, MhtResource>()\n const byCid = new Map<string, MhtResource>()\n for (const lf of leaves) {\n if (lf === rootHtmlLeaf) continue\n const res: MhtResource = {\n contentType: lf.contentType,\n charset: lf.charset,\n bytes: lf.bodyBytes ?? new Uint8Array(),\n }\n if (lf.contentLocation) {\n byLocation.set(lf.contentLocation, res)\n const abs = absolutize(lf.contentLocation, lf.contentLocation)\n if (abs !== lf.contentLocation) byLocation.set(abs, res)\n }\n if (lf.contentId) byCid.set(lf.contentId, res)\n }\n\n const rootBase = rootHtmlLeaf?.contentLocation || getHeader(headers, 'content-location') || ''\n const html = rootHtmlLeaf\n ? decodeCharset(rootHtmlLeaf.bodyBytes ?? new Uint8Array(), rootHtmlLeaf.charset)\n : null\n\n return {\n title: decodeWords(getHeader(headers, 'subject')),\n sourceUrl:\n getHeader(headers, 'snapshot-content-location') ||\n getHeader(headers, 'content-location') ||\n rootBase,\n date: getHeader(headers, 'date'),\n html,\n rootBase,\n byLocation,\n byCid,\n }\n}\n\nconst XLINK_NS = 'http://www.w3.org/1999/xlink'\n\n/**\n * Rewrite the parsed archive's root HTML so every captured resource reference points at a caller-supplied\n * blob URL, strip scripts, and inject {@link MHT_CSP}. Returns a complete HTML document string for the\n * sandboxed iframe. Browser-only (uses DOMParser — which neither runs scripts nor fetches subresources).\n *\n * `makeUrl(bytes, contentType)` is the caller's blob-URL factory (it tracks the URLs for later revocation).\n * Resources we can't resolve are left with their original URL — the CSP then blocks the request, so they\n * show as a broken image rather than leaking to the network.\n */\nexport function rewriteHtml(\n parsed: ParsedMht,\n makeUrl: (bytes: Uint8Array, contentType: string) => string,\n): string {\n const doc = new DOMParser().parseFromString(parsed.html ?? '', 'text/html')\n\n // One blob URL per distinct resource (an image referenced N times → one URL).\n const urlCache = new Map<MhtResource, string>()\n const urlFor = (res: MhtResource): string => {\n let u = urlCache.get(res)\n if (!u) {\n u = makeUrl(res.bytes, res.contentType || 'application/octet-stream')\n urlCache.set(res, u)\n }\n return u\n }\n\n const lookup = (ref: string, base: string): MhtResource | undefined => {\n if (!ref) return undefined\n if (/^cid:/i.test(ref)) {\n const id = unwrapId(ref.slice(4))\n return parsed.byCid.get(id) ?? parsed.byCid.get(decodeURIComponent(id))\n }\n if (/^(data|blob|javascript|about):/i.test(ref)) return undefined\n const abs = absolutize(ref, base)\n return parsed.byLocation.get(abs) ?? parsed.byLocation.get(ref)\n }\n\n // Rewrite `url(...)` and `@import` targets inside a CSS string (inline <style>, style=\"\", or a stylesheet).\n const rewriteCss = (css: string, base: string): string => {\n let out = css.replace(/url\\(\\s*(['\"]?)([^'\")]+)\\1\\s*\\)/gi, (whole, _q: string, ref: string) => {\n const res = lookup(ref, base)\n return res ? `url(\"${urlFor(res)}\")` : whole\n })\n out = out.replace(/@import\\s+(['\"])([^'\"]+)\\1/gi, (whole, _q: string, ref: string) => {\n const res = lookup(ref, base)\n return res ? `@import \"${urlFor(res)}\"` : whole\n })\n return out\n }\n\n const setAttrUrl = (el: Element, attr: string): void => {\n const ref = el.getAttribute(attr)\n if (!ref) return\n const res = lookup(ref, parsed.rootBase)\n if (res) el.setAttribute(attr, urlFor(res))\n }\n\n // Drop scripts, <base> (would skew URL resolution), and any document-supplied CSP (ours must win).\n doc.querySelectorAll('script, base').forEach((el) => el.remove())\n doc.querySelectorAll('meta[http-equiv]').forEach((m) => {\n if ((m.getAttribute('http-equiv') || '').toLowerCase() === 'content-security-policy') m.remove()\n })\n\n // Linked stylesheets: rewrite the CSS body's url()s against the stylesheet's own base, then re-blob it.\n doc.querySelectorAll('link[rel~=\"stylesheet\"][href]').forEach((el) => {\n const ref = el.getAttribute('href')\n if (!ref) return\n const res = lookup(ref, parsed.rootBase)\n if (!res) return\n const cssBase = absolutize(ref, parsed.rootBase)\n const css = rewriteCss(decodeCharset(res.bytes, res.charset), cssBase)\n el.setAttribute('href', makeUrl(new TextEncoder().encode(css), 'text/css'))\n })\n\n // Plain single-URL resource attributes.\n const ATTRS: [string, string][] = [\n ['img', 'src'],\n ['input[type=\"image\"]', 'src'],\n ['source', 'src'],\n ['video', 'src'],\n ['video', 'poster'],\n ['audio', 'src'],\n ['track', 'src'],\n ['embed', 'src'],\n ['object', 'data'],\n ]\n for (const [sel, attr] of ATTRS) {\n doc.querySelectorAll(sel).forEach((el) => setAttrUrl(el, attr))\n }\n\n // SVG <image href> / xlink:href.\n doc.querySelectorAll('image').forEach((el) => {\n setAttrUrl(el, 'href')\n const xref = el.getAttributeNS(XLINK_NS, 'href')\n if (xref) {\n const res = lookup(xref, parsed.rootBase)\n if (res) el.setAttributeNS(XLINK_NS, 'href', urlFor(res))\n }\n })\n\n // srcset (img / source): a comma list of `url [descriptor]` candidates.\n doc.querySelectorAll('img[srcset], source[srcset]').forEach((el) => {\n const ss = el.getAttribute('srcset')\n if (!ss) return\n const out = ss\n .split(',')\n .map((part) => {\n const seg = part.trim()\n if (!seg) return seg\n const sp = seg.split(/\\s+/)\n const res = lookup(sp[0], parsed.rootBase)\n if (res) sp[0] = urlFor(res)\n return sp.join(' ')\n })\n .join(', ')\n el.setAttribute('srcset', out)\n })\n\n // Inline style=\"\" and <style> blocks.\n doc.querySelectorAll('[style]').forEach((el) => {\n const s = el.getAttribute('style')\n if (s && s.includes('url(')) el.setAttribute('style', rewriteCss(s, parsed.rootBase))\n })\n doc.querySelectorAll('style').forEach((el) => {\n el.textContent = rewriteCss(el.textContent ?? '', parsed.rootBase)\n })\n\n // Inject our hardened CSP as the first thing in <head> (intersects with — can't be loosened by — any other).\n const meta = doc.createElement('meta')\n meta.setAttribute('http-equiv', 'Content-Security-Policy')\n meta.setAttribute('content', MHT_CSP)\n doc.head.insertBefore(meta, doc.head.firstChild)\n\n return '<!doctype html>\\n' + doc.documentElement.outerHTML\n}\n"],"mappings":";;AAqDA,IAAa,IACX;AAKF,SAAS,EAAW,GAAa,GAAsB;CACrD,IAAI;EACF,OAAO,IAAI,IAAI,GAAK,KAAQ,KAAA,CAAS,CAAC,CAAC;CACzC,QAAQ;EACN,OAAO;CACT;AACF;AAGA,SAAS,EAAS,GAAoB;CACpC,OAAO,EAAG,KAAK,CAAC,CAAC,QAAQ,UAAU,EAAE;AACvC;AAGA,SAAgB,EAAS,GAA8B;CACrD,IAAM,IAAM,EAAc,CAAK,GACzB,IAAO,EAAY,CAAG,GACtB,IAAU,EAAa,EAAiB,CAAG,CAAC,CAAC,EAAE,GAE/C,IAAmB,CAAC;CAC1B,EAAc,GAAM,CAAM;CAG1B,IAAM,IAAQ,EAAS,EAAK,SAAS,SAAS,EAAE,GAC5C;CAEJ,AADI,MAAO,IAAe,EAAO,MAAM,MAAM,EAAE,cAAc,CAAK,IAClE,AAAmB,MAAe,EAAO,MAAM,MAAM,EAAE,gBAAgB,WAAW;CAGlF,IAAM,oBAAa,IAAI,IAAyB,GAC1C,oBAAQ,IAAI,IAAyB;CAC3C,KAAK,IAAM,KAAM,GAAQ;EACvB,IAAI,MAAO,GAAc;EACzB,IAAM,IAAmB;GACvB,aAAa,EAAG;GAChB,SAAS,EAAG;GACZ,OAAO,EAAG,aAAa,IAAI,WAAW;EACxC;EACA,IAAI,EAAG,iBAAiB;GACtB,EAAW,IAAI,EAAG,iBAAiB,CAAG;GACtC,IAAM,IAAM,EAAW,EAAG,iBAAiB,EAAG,eAAe;GAC7D,AAAI,MAAQ,EAAG,mBAAiB,EAAW,IAAI,GAAK,CAAG;EACzD;EACA,AAAI,EAAG,aAAW,EAAM,IAAI,EAAG,WAAW,CAAG;CAC/C;CAEA,IAAM,IAAW,GAAc,mBAAmB,EAAU,GAAS,kBAAkB,KAAK,IACtF,IAAO,IACT,EAAc,EAAa,aAAa,IAAI,WAAW,GAAG,EAAa,OAAO,IAC9E;CAEJ,OAAO;EACL,OAAO,EAAY,EAAU,GAAS,SAAS,CAAC;EAChD,WACE,EAAU,GAAS,2BAA2B,KAC9C,EAAU,GAAS,kBAAkB,KACrC;EACF,MAAM,EAAU,GAAS,MAAM;EAC/B;EACA;EACA;EACA;CACF;AACF;AAEA,IAAM,IAAW;AAWjB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAM,IAAI,UAAU,CAAC,CAAC,gBAAgB,EAAO,QAAQ,IAAI,WAAW,GAGpE,oBAAW,IAAI,IAAyB,GACxC,KAAU,MAA6B;EAC3C,IAAI,IAAI,EAAS,IAAI,CAAG;EAKxB,OAJK,MACH,IAAI,EAAQ,EAAI,OAAO,EAAI,eAAe,0BAA0B,GACpE,EAAS,IAAI,GAAK,CAAC,IAEd;CACT,GAEM,KAAU,GAAa,MAA0C;EACrE,IAAI,CAAC,GAAK;EACV,IAAI,SAAS,KAAK,CAAG,GAAG;GACtB,IAAM,IAAK,EAAS,EAAI,MAAM,CAAC,CAAC;GAChC,OAAO,EAAO,MAAM,IAAI,CAAE,KAAK,EAAO,MAAM,IAAI,mBAAmB,CAAE,CAAC;EACxE;EACA,IAAI,kCAAkC,KAAK,CAAG,GAAG;EACjD,IAAM,IAAM,EAAW,GAAK,CAAI;EAChC,OAAO,EAAO,WAAW,IAAI,CAAG,KAAK,EAAO,WAAW,IAAI,CAAG;CAChE,GAGM,KAAc,GAAa,MAAyB;EACxD,IAAI,IAAM,EAAI,QAAQ,sCAAsC,GAAO,GAAY,MAAgB;GAC7F,IAAM,IAAM,EAAO,GAAK,CAAI;GAC5B,OAAO,IAAM,QAAQ,EAAO,CAAG,EAAE,MAAM;EACzC,CAAC;EAKD,OAJA,IAAM,EAAI,QAAQ,iCAAiC,GAAO,GAAY,MAAgB;GACpF,IAAM,IAAM,EAAO,GAAK,CAAI;GAC5B,OAAO,IAAM,YAAY,EAAO,CAAG,EAAE,KAAK;EAC5C,CAAC,GACM;CACT,GAEM,KAAc,GAAa,MAAuB;EACtD,IAAM,IAAM,EAAG,aAAa,CAAI;EAChC,IAAI,CAAC,GAAK;EACV,IAAM,IAAM,EAAO,GAAK,EAAO,QAAQ;EACvC,AAAI,KAAK,EAAG,aAAa,GAAM,EAAO,CAAG,CAAC;CAC5C;CASA,AANA,EAAI,iBAAiB,cAAc,CAAC,CAAC,SAAS,MAAO,EAAG,OAAO,CAAC,GAChE,EAAI,iBAAiB,kBAAkB,CAAC,CAAC,SAAS,MAAM;EACtD,CAAK,EAAE,aAAa,YAAY,KAAK,GAAA,CAAI,YAAY,MAAM,6BAA2B,EAAE,OAAO;CACjG,CAAC,GAGD,EAAI,iBAAiB,iCAA+B,CAAC,CAAC,SAAS,MAAO;EACpE,IAAM,IAAM,EAAG,aAAa,MAAM;EAClC,IAAI,CAAC,GAAK;EACV,IAAM,IAAM,EAAO,GAAK,EAAO,QAAQ;EACvC,IAAI,CAAC,GAAK;EACV,IAAM,IAAU,EAAW,GAAK,EAAO,QAAQ,GACzC,IAAM,EAAW,EAAc,EAAI,OAAO,EAAI,OAAO,GAAG,CAAO;EACrE,EAAG,aAAa,QAAQ,EAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,CAAG,GAAG,UAAU,CAAC;CAC5E,CAAC;CAcD,KAAK,IAAM,CAAC,GAAK,MAAS;EAVxB,CAAC,OAAO,KAAK;EACb,CAAC,yBAAuB,KAAK;EAC7B,CAAC,UAAU,KAAK;EAChB,CAAC,SAAS,KAAK;EACf,CAAC,SAAS,QAAQ;EAClB,CAAC,SAAS,KAAK;EACf,CAAC,SAAS,KAAK;EACf,CAAC,SAAS,KAAK;EACf,CAAC,UAAU,MAAM;CAEO,GACxB,EAAI,iBAAiB,CAAG,CAAC,CAAC,SAAS,MAAO,EAAW,GAAI,CAAI,CAAC;CAoChE,AAhCA,EAAI,iBAAiB,OAAO,CAAC,CAAC,SAAS,MAAO;EAC5C,EAAW,GAAI,MAAM;EACrB,IAAM,IAAO,EAAG,eAAe,GAAU,MAAM;EAC/C,IAAI,GAAM;GACR,IAAM,IAAM,EAAO,GAAM,EAAO,QAAQ;GACxC,AAAI,KAAK,EAAG,eAAe,GAAU,QAAQ,EAAO,CAAG,CAAC;EAC1D;CACF,CAAC,GAGD,EAAI,iBAAiB,6BAA6B,CAAC,CAAC,SAAS,MAAO;EAClE,IAAM,IAAK,EAAG,aAAa,QAAQ;EACnC,IAAI,CAAC,GAAI;EACT,IAAM,IAAM,EACT,MAAM,GAAG,CAAC,CACV,KAAK,MAAS;GACb,IAAM,IAAM,EAAK,KAAK;GACtB,IAAI,CAAC,GAAK,OAAO;GACjB,IAAM,IAAK,EAAI,MAAM,KAAK,GACpB,IAAM,EAAO,EAAG,IAAI,EAAO,QAAQ;GAEzC,OADI,MAAK,EAAG,KAAK,EAAO,CAAG,IACpB,EAAG,KAAK,GAAG;EACpB,CAAC,CAAC,CACD,KAAK,IAAI;EACZ,EAAG,aAAa,UAAU,CAAG;CAC/B,CAAC,GAGD,EAAI,iBAAiB,SAAS,CAAC,CAAC,SAAS,MAAO;EAC9C,IAAM,IAAI,EAAG,aAAa,OAAO;EACjC,AAAI,KAAK,EAAE,SAAS,MAAM,KAAG,EAAG,aAAa,SAAS,EAAW,GAAG,EAAO,QAAQ,CAAC;CACtF,CAAC,GACD,EAAI,iBAAiB,OAAO,CAAC,CAAC,SAAS,MAAO;EAC5C,EAAG,cAAc,EAAW,EAAG,eAAe,IAAI,EAAO,QAAQ;CACnE,CAAC;CAGD,IAAM,IAAO,EAAI,cAAc,MAAM;CAKrC,OAJA,EAAK,aAAa,cAAc,yBAAyB,GACzD,EAAK,aAAa,WAAW,CAAO,GACpC,EAAI,KAAK,aAAa,GAAM,EAAI,KAAK,UAAU,GAExC,sBAAsB,EAAI,gBAAgB;AACnD"}
package/dist/lib/midi.js CHANGED
@@ -82,3 +82,5 @@ function e(e) {
82
82
  }
83
83
  //#endregion
84
84
  export { e as parseMidi };
85
+
86
+ //# sourceMappingURL=midi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"midi.js","names":[],"sources":["../../src/lib/midi.ts"],"sourcesContent":["/**\n * Hand-rolled, zero-dependency Standard MIDI File (.mid/.midi) parser for the side viewer's best-effort\n * preview. The browser can't *play* MIDI (there's no built-in synthesizer and self-hosting a soundfont is out\n * of scope), so the viewer instead VISUALIZES the music as a piano roll. This extracts what that needs: the\n * note events (pitch / timing / track) plus header info and an approximate duration.\n *\n * Timing is approximate by design: it uses the first `set_tempo` it sees (or 120 BPM) for the whole file, so\n * songs with tempo changes will be slightly off — fine for a visual overview. SMPTE-division files fall back\n * to a nominal ticks-per-quarter. Note-ons with velocity 0 are treated as note-offs (the common shorthand).\n */\n\nexport interface MidiNote {\n track: number\n channel: number\n pitch: number // 0..127\n startTick: number\n endTick: number\n velocity: number // 1..127\n}\n\nexport interface ParsedMidi {\n format: number\n trackCount: number\n division: number // ticks per quarter note (or nominal fallback for SMPTE)\n notes: MidiNote[]\n totalTicks: number\n durationSec: number\n tempoBpm: number\n}\n\nexport function parseMidi(buf: ArrayBuffer): ParsedMidi {\n const dv = new DataView(buf)\n let p = 0\n const u8 = (): number => dv.getUint8(p++)\n const u16 = (): number => {\n const v = dv.getUint16(p)\n p += 2\n return v\n }\n const u32 = (): number => {\n const v = dv.getUint32(p)\n p += 4\n return v\n }\n const tag = (): string => String.fromCharCode(u8(), u8(), u8(), u8())\n // MIDI variable-length quantity.\n const varLen = (): number => {\n let value = 0\n for (let i = 0; i < 4; i++) {\n const b = u8()\n value = (value << 7) | (b & 0x7f)\n if (!(b & 0x80)) break\n }\n return value\n }\n\n if (buf.byteLength < 14 || tag() !== 'MThd') throw new Error('不是有效的 MIDI 文件')\n const headerLen = u32()\n const format = u16()\n const ntrks = u16()\n const rawDivision = u16()\n p = 8 + headerLen // skip to the first track (past any extra header bytes)\n\n const smpte = (rawDivision & 0x8000) !== 0\n const division = smpte ? 480 : rawDivision || 480\n\n const notes: MidiNote[] = []\n let tempoUs = 500000 // 120 BPM default\n let tempoSet = false\n let totalTicks = 0\n\n for (let t = 0; t < ntrks && p + 8 <= dv.byteLength; t++) {\n if (tag() !== 'MTrk') break\n const len = u32()\n const end = Math.min(p + len, dv.byteLength)\n let tick = 0\n let status = 0\n // key = (channel << 8) | pitch → the open note's start tick + velocity.\n const active = new Map<number, { startTick: number; velocity: number }>()\n const closeNote = (channel: number, pitch: number): void => {\n const key = (channel << 8) | pitch\n const a = active.get(key)\n if (a) {\n notes.push({\n track: t,\n channel,\n pitch,\n startTick: a.startTick,\n endTick: tick,\n velocity: a.velocity,\n })\n active.delete(key)\n if (tick > totalTicks) totalTicks = tick\n }\n }\n\n while (p < end) {\n tick += varLen()\n let b = u8()\n if (b & 0x80) {\n status = b\n } else {\n p-- // running status: reuse the previous status, `b` is the first data byte\n }\n if (status === 0xff) {\n // meta event\n const type = u8()\n const mlen = varLen()\n if (type === 0x51 && mlen === 3) {\n const us = (u8() << 16) | (u8() << 8) | u8()\n if (!tempoSet) {\n tempoUs = us\n tempoSet = true\n }\n } else {\n p += mlen\n }\n } else if (status === 0xf0 || status === 0xf7) {\n // sysex — skip\n p += varLen()\n } else {\n const hi = status & 0xf0\n const ch = status & 0x0f\n if (hi === 0x90) {\n const pitch = u8()\n const vel = u8()\n if (vel > 0) active.set((ch << 8) | pitch, { startTick: tick, velocity: vel })\n else closeNote(ch, pitch)\n } else if (hi === 0x80) {\n const pitch = u8()\n u8() // release velocity\n closeNote(ch, pitch)\n } else if (hi === 0xa0 || hi === 0xb0 || hi === 0xe0) {\n p += 2 // two data bytes\n } else if (hi === 0xc0 || hi === 0xd0) {\n p += 1 // one data byte\n } else {\n break // unknown status — bail out of this track\n }\n }\n }\n // Close any notes left hanging at the track's end.\n for (const [key, a] of active) {\n const pitch = key & 0xff\n const channel = key >> 8\n notes.push({\n track: t,\n channel,\n pitch,\n startTick: a.startTick,\n endTick: tick,\n velocity: a.velocity,\n })\n }\n if (tick > totalTicks) totalTicks = tick\n p = end // realign to the declared track length\n }\n\n const secPerTick = tempoUs / 1e6 / division\n return {\n format,\n trackCount: ntrks,\n division,\n notes,\n totalTicks,\n durationSec: totalTicks * secPerTick,\n tempoBpm: Math.round(60e6 / tempoUs),\n }\n}\n"],"mappings":"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"}
package/dist/lib/mime.js CHANGED
@@ -149,3 +149,5 @@ function v(e, t) {
149
149
  }
150
150
  //#endregion
151
151
  export { t as bytesToBinary, v as collectLeaves, i as decodeCharset, o as decodeWords, l as getHeader, _ as parseEntity, c as parseHeaders, s as splitHeadersBody };
152
+
153
+ //# sourceMappingURL=mime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.js","names":[],"sources":["../../src/lib/mime.ts"],"sourcesContent":["/**\n * Hand-rolled MIME core (RFC 822 / 2045 / 2047 / 2231) shared by the side-viewer's MIME-container previews.\n *\n * Zero-dependency, in the spirit of the project's other parsers (lib/zip.ts, lib/binobj.ts). Both an `.eml`\n * email (lib/eml.ts) and a `.mht`/`.mhtml` web archive (lib/mht.ts) are the SAME on the wire: RFC 822 headers\n * + a body that may be a tree of multipart entities, each with its own Content-Type / Content-Transfer-\n * Encoding / charset. This module owns that generic machinery — parse the container into an {@link Entity}\n * tree, transfer-decode (base64 / quoted-printable) and charset-decode (TextDecoder) each leaf — and the two\n * format-specific modules flatten the tree into their own render-ready shapes.\n *\n * Bytes vs. text: the transport is treated as a 1:1 binary string (each byte → one char in [0,255]) so we\n * can split on boundaries / unfold headers with plain string ops while keeping leaf bytes exact. Per-part we\n * then transfer-decode and charset-decode to recover real text / bytes. Real attachments / resources are\n * virtually always base64/QP (7-bit safe), so the binary string round-trips losslessly even for non-UTF-8.\n */\n\n// Charset labels TextDecoder rejects (or that aren't registered) → a label it accepts. ASCII is a UTF-8\n// subset, so decoding it as UTF-8 is lossless; the cp1252/ansi spellings map to the registered name.\nconst CHARSET_ALIAS: Record<string, string> = {\n 'us-ascii': 'utf-8',\n ascii: 'utf-8',\n 'ansi_x3.4-1968': 'utf-8',\n 'iso-ir-6': 'utf-8',\n ansi: 'windows-1252',\n cp1252: 'windows-1252',\n}\n\n/** Pack bytes into a 1:1 binary string (each byte → one char in [0,255]); chunked to bound arg count. */\nexport function bytesToBinary(bytes: Uint8Array): string {\n let out = ''\n const CHUNK = 0x8000\n for (let i = 0; i < bytes.length; i += CHUNK) {\n out += String.fromCharCode(...bytes.subarray(i, i + CHUNK))\n }\n return out\n}\n\n/** Inverse of {@link bytesToBinary}: a binary string back to its exact bytes. */\nexport function binaryToBytes(s: string): Uint8Array {\n const out = new Uint8Array(s.length)\n for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i) & 0xff\n return out\n}\n\n/** Decode base64 (tolerant of embedded whitespace/newlines) to bytes. */\nexport function base64ToBytes(b64: string): Uint8Array {\n const clean = b64.replace(/[^A-Za-z0-9+/=]/g, '')\n return binaryToBytes(atob(clean))\n}\n\n/** Decode bytes with a (possibly messy) charset label, falling back to UTF-8 then a raw binary string. */\nexport function decodeCharset(bytes: Uint8Array, charset: string): string {\n // RFC 2047 charsets may carry a `*language` suffix (e.g. `utf-8*en`) — strip it before labelling.\n let label = (charset || 'utf-8').trim().toLowerCase().split('*')[0]\n label = CHARSET_ALIAS[label] ?? label\n try {\n return new TextDecoder(label, { fatal: false }).decode(bytes)\n } catch {\n try {\n return new TextDecoder('utf-8', { fatal: false }).decode(bytes)\n } catch {\n return bytesToBinary(bytes)\n }\n }\n}\n\n/** Decode quoted-printable text (soft line-breaks dropped, `=XX` → byte) to a binary string. */\nexport function decodeQuotedPrintable(s: string): string {\n return s\n .replace(/=\\r?\\n/g, '')\n .replace(/=([0-9A-Fa-f]{2})/g, (_, h: string) => String.fromCharCode(parseInt(h, 16)))\n}\n\n/**\n * Decode RFC 2047 encoded-words in a header value (`=?charset?B|Q?text?=`). Adjacent encoded words\n * separated only by whitespace are concatenated with the whitespace removed (§6.2).\n */\nexport function decodeWords(input: string): string {\n if (!input || !input.includes('=?')) return input\n const collapsed = input.replace(/\\?=\\s+=\\?/g, '?==?')\n return collapsed.replace(\n /=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?=/g,\n (whole, charset: string, enc: string, data: string) => {\n try {\n let bytes: Uint8Array\n if (enc.toUpperCase() === 'B') {\n bytes = base64ToBytes(data)\n } else {\n const q = data\n .replace(/_/g, ' ')\n .replace(/=([0-9A-Fa-f]{2})/g, (_, h: string) => String.fromCharCode(parseInt(h, 16)))\n bytes = binaryToBytes(q)\n }\n return decodeCharset(bytes, charset)\n } catch {\n return whole\n }\n },\n )\n}\n\nexport interface HeaderField {\n name: string\n value: string\n}\n\n/** Split a raw entity (binary string) into its header block and body at the first blank line. */\nexport function splitHeadersBody(raw: string): [string, string] {\n const m = raw.match(/\\r?\\n\\r?\\n/)\n if (!m || m.index === undefined) return [raw, '']\n return [raw.slice(0, m.index), raw.slice(m.index + m[0].length)]\n}\n\n/** Parse a header block into ordered fields, unfolding continuation (leading-whitespace) lines. */\nexport function parseHeaders(block: string): HeaderField[] {\n const out: HeaderField[] = []\n for (const line of block.split(/\\r?\\n/)) {\n if (/^[ \\t]/.test(line) && out.length) {\n // Folded continuation: unfolding removes the CRLF; collapse the indent to a single space.\n out[out.length - 1].value += ' ' + line.replace(/^[ \\t]+/, '')\n } else {\n const ci = line.indexOf(':')\n if (ci > 0) out.push({ name: line.slice(0, ci).trim(), value: line.slice(ci + 1).trim() })\n }\n }\n return out\n}\n\n/** First header value (case-insensitive), '' when absent. */\nexport function getHeader(headers: HeaderField[], name: string): string {\n const lc = name.toLowerCase()\n return headers.find((h) => h.name.toLowerCase() === lc)?.value ?? ''\n}\n\nexport interface ContentType {\n type: string\n params: Record<string, string>\n}\n\n/** Split a structured header value on `;`, ignoring separators inside quotes. */\nexport function splitParams(value: string): string[] {\n const out: string[] = []\n let cur = ''\n let inQ = false\n for (const c of value) {\n if (c === '\"') {\n inQ = !inQ\n cur += c\n } else if (c === ';' && !inQ) {\n out.push(cur)\n cur = ''\n } else {\n cur += c\n }\n }\n if (cur.trim()) out.push(cur)\n return out\n}\n\n/** Parse a Content-Type / Content-Disposition value into its type token + lowercased params. */\nexport function parseTyped(value: string): ContentType {\n const parts = splitParams(value)\n const type = (parts.shift() ?? '').trim().toLowerCase()\n const params: Record<string, string> = {}\n for (const p of parts) {\n const eq = p.indexOf('=')\n if (eq < 0) continue\n const k = p.slice(0, eq).trim().toLowerCase()\n let v = p.slice(eq + 1).trim()\n if (v.startsWith('\"') && v.endsWith('\"')) v = v.slice(1, -1)\n params[k] = v\n }\n return { type, params }\n}\n\n/** Percent-decode an RFC 2231 extended value's encoded bytes with the given charset. */\nfunction percentDecode(s: string, charset: string): string {\n const bytes: number[] = []\n for (let i = 0; i < s.length; i++) {\n if (s[i] === '%' && i + 2 < s.length) {\n bytes.push(parseInt(s.slice(i + 1, i + 3), 16))\n i += 2\n } else {\n bytes.push(s.charCodeAt(i) & 0xff)\n }\n }\n return decodeCharset(Uint8Array.from(bytes), charset || 'utf-8')\n}\n\n/** Decode a single RFC 2231 extended value (`charset'lang'percent-encoded`). */\nfunction decodeExtValue(v: string): string {\n const m = v.match(/^([^']*)'[^']*'(.*)$/)\n return m ? percentDecode(m[2], m[1]) : percentDecode(v, '')\n}\n\n/**\n * Resolve a parameter (`filename` / `name`) across its RFC 2231 spellings: a plain quoted value (with\n * RFC 2047 encoded-words decoded), a single extended `name*=`, or `name*0*`/`name*1*` continuations.\n */\nexport function paramValue(params: Record<string, string>, base: string): string {\n if (params[base + '*'] !== undefined) return decodeExtValue(params[base + '*'])\n if (params[base] !== undefined) return decodeWords(params[base])\n if (params[`${base}*0`] !== undefined || params[`${base}*0*`] !== undefined) {\n let s = ''\n let cs = ''\n for (let i = 0; ; i++) {\n const ext = params[`${base}*${i}*`]\n const plain = params[`${base}*${i}`]\n if (ext !== undefined) {\n if (i === 0) {\n const m = ext.match(/^([^']*)'[^']*'(.*)$/)\n if (m) {\n cs = m[1]\n s += percentDecode(m[2], cs)\n } else {\n s += percentDecode(ext, cs)\n }\n } else {\n s += percentDecode(ext, cs)\n }\n } else if (plain !== undefined) {\n s += plain\n } else {\n break\n }\n }\n return s\n }\n return ''\n}\n\n/** Transfer-decode a leaf body (binary string) per its Content-Transfer-Encoding into exact bytes. */\nexport function decodeBody(bodyBin: string, encoding: string): Uint8Array {\n const enc = (encoding || '').trim().toLowerCase()\n if (enc === 'base64') return base64ToBytes(bodyBin)\n if (enc === 'quoted-printable') return binaryToBytes(decodeQuotedPrintable(bodyBin))\n // 7bit / 8bit / binary / none → the bytes are already literal.\n return binaryToBytes(bodyBin)\n}\n\n/**\n * Split a multipart body (binary string) into its part substrings (headers + body each). Boundary\n * delimiter lines are `--boundary` at a line start; the closing one is `--boundary--`. The CRLF preceding\n * a delimiter belongs to the boundary, so it's excluded from the preceding part.\n */\nexport function splitMultipart(bodyBin: string, boundary: string): string[] {\n const esc = boundary.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const re = new RegExp(`(?:^|\\\\r\\\\n|\\\\n)--${esc}(--)?[ \\\\t]*(?:\\\\r\\\\n|\\\\n|$)`, 'g')\n const parts: string[] = []\n let m: RegExpExecArray | null\n let contentStart = -1\n while ((m = re.exec(bodyBin)) !== null) {\n if (contentStart >= 0) parts.push(bodyBin.slice(contentStart, m.index))\n if (m[1] === '--') break // closing delimiter\n contentStart = re.lastIndex\n }\n return parts\n}\n\n/** One MIME entity: a leaf (with decoded {@link bodyBytes}) or a multipart node (with child {@link parts}). */\nexport interface Entity {\n contentType: string\n charset: string\n encoding: string\n disposition: string\n filename: string\n /** Content-ID without the angle brackets, '' if none — the key a `cid:` ref resolves to (email inline). */\n contentId: string\n /** Content-Location URI, '' if none — the key a web archive's resource references resolve to (MHT). */\n contentLocation: string\n /** Raw Content-Type params (lowercased), e.g. `boundary` / `start` / `type` — for MHT root selection. */\n ctParams: Record<string, string>\n isMultipart: boolean\n parts: Entity[]\n bodyBytes: Uint8Array | null\n}\n\n/** Recursively parse one MIME entity (binary string) into the {@link Entity} tree. */\nexport function parseEntity(rawBin: string, depth = 0): Entity {\n const [head, body] = splitHeadersBody(rawBin)\n const headers = parseHeaders(head)\n const ct = parseTyped(getHeader(headers, 'content-type') || 'text/plain')\n const type = ct.type || 'text/plain'\n const cd = parseTyped(getHeader(headers, 'content-disposition'))\n let contentId = getHeader(headers, 'content-id').trim()\n if (contentId.startsWith('<') && contentId.endsWith('>')) contentId = contentId.slice(1, -1)\n\n const ent: Entity = {\n contentType: type,\n charset: ct.params.charset || '',\n encoding: getHeader(headers, 'content-transfer-encoding'),\n disposition: cd.type || '',\n filename: paramValue(cd.params, 'filename') || paramValue(ct.params, 'name') || '',\n contentId,\n // Content-Location is a bare URI (no angle brackets) — just trim.\n contentLocation: getHeader(headers, 'content-location').trim(),\n ctParams: ct.params,\n isMultipart: false,\n parts: [],\n bodyBytes: null,\n }\n\n if (type.startsWith('multipart/') && ct.params.boundary && depth < 20) {\n ent.isMultipart = true\n for (const sub of splitMultipart(body, ct.params.boundary)) {\n ent.parts.push(parseEntity(sub, depth + 1))\n }\n } else {\n ent.bodyBytes = decodeBody(body, ent.encoding)\n }\n return ent\n}\n\n/** Depth-first collect every leaf (non-multipart) entity. */\nexport function collectLeaves(ent: Entity, out: Entity[]): void {\n if (ent.isMultipart) {\n for (const p of ent.parts) collectLeaves(p, out)\n } else {\n out.push(ent)\n }\n}\n"],"mappings":"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"}
@@ -111,3 +111,5 @@ function d(e, t) {
111
111
  }
112
112
  //#endregion
113
113
  export { d as looksLikeMindMap, u as parseMindMap };
114
+
115
+ //# sourceMappingURL=mindmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mindmap.js","names":[],"sources":["../../src/lib/mindmap.ts"],"sourcesContent":["/**\n * Parser for outline / mind-map files into a common tree, shared by the side viewer's MindMapView.\n *\n * Two input formats, both XML, both fundamentally a tree:\n * - OPML (.opml): `<opml><head><title/></head><body><outline text=… _note=… url=…>…</outline></body></opml>`,\n * `<outline>` nests arbitrarily. Used for RSS feed lists, outlines, and some mind-map exports.\n * - FreeMind / Freeplane (.mm): `<map><node TEXT=… LINK=… COLOR=… FOLDED=…>…</node></map>`, `<node>` nests;\n * a node's label can also live in `<richcontent TYPE=\"NODE\">…html…</richcontent>`, notes in `TYPE=\"NOTE\"`.\n *\n * We parse with the browser DOMParser (guarded for SSR — the viewer is client-only, but stay defensive) and\n * normalize both into {@link MindNode}. Node ids are assigned during parse and are stable for the lifetime of a\n * parsed tree (the viewer caches the parse by file text), so they key the collapse/expand state.\n *\n * `.mm` is ALSO the Objective-C++ source extension, so callers must content-sniff with {@link looksLikeMindMap}\n * before treating a `.mm` as a mind map — an Objective-C++ `.mm` is not XML and would (rightly) fail this gate.\n */\n\nexport interface MindNode {\n /** Stable id within one parsed tree — keys collapse/expand state. */\n id: number\n /** Plain-text label (markup/whitespace flattened). */\n text: string\n /** Optional note (OPML `_note`, FreeMind `<richcontent TYPE=\"NOTE\">`) — shown as a hover tooltip. */\n note?: string\n /** Optional hyperlink (OPML `url`/`htmlUrl`/`xmlUrl`, FreeMind `LINK`) — rendered as an open-in-new-tab glyph. */\n link?: string\n /** Explicit text color (FreeMind `COLOR`), `#rgb`/`#rrggbb` only. */\n color?: string\n /** Explicit background color (FreeMind `BACKGROUND_COLOR`), `#rgb`/`#rrggbb` only. */\n bg?: string\n /** Authored initial fold state (FreeMind `FOLDED=\"true\"`) — the viewer seeds collapse from this. */\n foldedInit?: boolean\n children: MindNode[]\n}\n\nexport interface MindMap {\n format: 'opml' | 'freemind' | 'xmind'\n title: string\n root: MindNode\n /** Total node count (incl. root), for the viewer's summary line. */\n count: number\n}\n\n/** Lowercased child elements with the given local tag name. */\nfunction childrenByTag(el: Element, tag: string): Element[] {\n const out: Element[] = []\n for (const c of Array.from(el.children)) {\n if (c.tagName.toLowerCase() === tag) out.push(c)\n }\n return out\n}\n\n/** First child element with the given local tag name (optionally matching a `TYPE` attribute, case-insensitive). */\nfunction firstChildByTag(el: Element, tag: string, type?: string): Element | null {\n for (const c of Array.from(el.children)) {\n if (c.tagName.toLowerCase() !== tag) continue\n if (type && (attr(c, 'TYPE') || '').toLowerCase() !== type.toLowerCase()) continue\n return c\n }\n return null\n}\n\n/** Read the first present attribute among `names`, falling back to a case-insensitive scan (FreeMind uses UPPER). */\nfunction attr(el: Element, ...names: string[]): string | null {\n for (const n of names) {\n const v = el.getAttribute(n)\n if (v != null) return v\n }\n const lowered = names.map((n) => n.toLowerCase())\n for (const a of Array.from(el.attributes)) {\n if (lowered.includes(a.name.toLowerCase())) return a.value\n }\n return null\n}\n\n/** Collapse all whitespace (incl. newlines from flattened markup) to single spaces. */\nfunction flatten(s: string | null | undefined): string {\n return (s || '').replace(/\\s+/g, ' ').trim()\n}\n\n/** Accept only simple hex colors; ignore named/rgba() values we can't safely inline. */\nfunction normColor(c: string | null): string | undefined {\n if (!c) return undefined\n return /^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(c.trim()) ? c.trim() : undefined\n}\n\nfunction makeIdGen(): () => number {\n let n = 0\n return () => n++\n}\n\nfunction parseOpmlOutline(el: Element, id: () => number): MindNode {\n // `text` is the OPML 2.0 attribute; `title` is the older fallback. Both may carry HTML — flatten to text.\n const raw = attr(el, 'text', 'title') ?? ''\n const text = flatten(raw.includes('<') ? stripTags(raw) : raw)\n const note = flatten(attr(el, '_note', 'note') ?? '')\n const link = attr(el, 'url', 'htmlUrl', 'xmlUrl') ?? undefined\n return {\n id: id(),\n text,\n note: note || undefined,\n link: link || undefined,\n children: childrenByTag(el, 'outline').map((c) => parseOpmlOutline(c, id)),\n }\n}\n\nfunction stripTags(s: string): string {\n return s.replace(/<[^>]*>/g, ' ')\n}\n\nfunction parseFreemindNode(el: Element, id: () => number): MindNode {\n let text = attr(el, 'TEXT')\n if (text == null) {\n // Rich (HTML) node label — DOMParser already decoded entities, so textContent is the readable text.\n const rc = firstChildByTag(el, 'richcontent', 'NODE') ?? firstChildByTag(el, 'richcontent')\n text = rc ? rc.textContent : ''\n }\n const noteEl = firstChildByTag(el, 'richcontent', 'NOTE')\n return {\n id: id(),\n text: flatten(text),\n note: noteEl ? flatten(noteEl.textContent) || undefined : undefined,\n link: attr(el, 'LINK') ?? undefined,\n color: normColor(attr(el, 'COLOR')),\n bg: normColor(attr(el, 'BACKGROUND_COLOR')),\n foldedInit: (attr(el, 'FOLDED') || '').toLowerCase() === 'true',\n children: childrenByTag(el, 'node').map((c) => parseFreemindNode(c, id)),\n }\n}\n\nfunction countNodes(n: MindNode): number {\n let c = 1\n for (const k of n.children) c += countNodes(k)\n return c\n}\n\n/**\n * Parse OPML or FreeMind XML into a {@link MindMap}. `kind` picks the parser, but the actual root element wins\n * if it disagrees (so a mislabeled file still parses). Throws on malformed XML or an unrecognized root.\n */\nexport function parseMindMap(text: string, kind: 'opml' | 'mm', fallbackTitle = ''): MindMap {\n if (typeof DOMParser === 'undefined') {\n // SSR / no-DOM fallback: an empty tree rather than a crash (the real parse runs client-side).\n return {\n format: kind === 'opml' ? 'opml' : 'freemind',\n title: fallbackTitle,\n root: { id: 0, text: fallbackTitle, children: [] },\n count: 1,\n }\n }\n const doc = new DOMParser().parseFromString(text, 'application/xml')\n if (doc.querySelector('parsererror')) throw new Error('XML 解析失败')\n\n const id = makeIdGen()\n const opml = doc.querySelector('opml')\n const map = doc.querySelector('map')\n\n if (opml || (kind === 'opml' && !map)) {\n const root = opml ?? doc.documentElement\n const titleEl = root.querySelector('head > title') ?? doc.querySelector('head > title')\n const title = flatten(titleEl?.textContent) || fallbackTitle || '大纲'\n const body = root.querySelector('body') ?? doc.querySelector('body')\n const tops = body ? childrenByTag(body, 'outline') : []\n // A single titleless top outline becomes the root itself; otherwise wrap the tops under a title node.\n let rootNode: MindNode\n if (!flatten(titleEl?.textContent) && tops.length === 1) {\n rootNode = parseOpmlOutline(tops[0], id)\n } else {\n rootNode = { id: id(), text: title, children: tops.map((t) => parseOpmlOutline(t, id)) }\n }\n return {\n format: 'opml',\n title: rootNode.text || title,\n root: rootNode,\n count: countNodes(rootNode),\n }\n }\n\n if (map) {\n const rootEl = childrenByTag(map, 'node')[0]\n const rootNode = rootEl\n ? parseFreemindNode(rootEl, id)\n : { id: id(), text: fallbackTitle || '思维导图', children: [] }\n return {\n format: 'freemind',\n title: rootNode.text || fallbackTitle || '思维导图',\n root: rootNode,\n count: countNodes(rootNode),\n }\n }\n\n throw new Error('无法识别的文件结构(既非 OPML 也非 FreeMind)')\n}\n\n/**\n * Cheap content sniff to confirm a file really is a mind map before showing the diagram. `.opml` is unambiguous;\n * `.mm` is gated because the extension is shared with Objective-C++ — a non-XML `.mm` fails here and falls back\n * to plain highlighted source. Only the file head is inspected.\n */\nexport function looksLikeMindMap(text: string, ext: string): boolean {\n const head = (text || '').slice(0, 4096)\n if (ext === 'opml') return /<opml[\\s>]/i.test(head)\n if (ext === 'mm') return /<map[\\s>]/i.test(head) && /<node[\\s>]/i.test(head)\n return false\n}\n"],"mappings":"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"}
package/dist/lib/mobi.js CHANGED
@@ -66,3 +66,5 @@ function i(e) {
66
66
  }
67
67
  //#endregion
68
68
  export { i as parseMobi };
69
+
70
+ //# sourceMappingURL=mobi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobi.js","names":[],"sources":["../../src/lib/mobi.ts"],"sourcesContent":["/**\n * Hand-rolled, zero-dependency BEST-EFFORT MOBI / AZW3 text extractor for the side viewer.\n *\n * Kindle formats are a Palm Database (PDB) holding a MOBI/KF8 header plus text records. This parses the PDB,\n * reads the PalmDOC/MOBI header, strips each text record's trailing-data entries, decompresses (PalmDOC LZ77,\n * or uncompressed), and concatenates the result into the book's HTML — which the viewer shows in a sandboxed\n * iframe. It is intentionally PARTIAL: HUFF/CDIC-compressed books (compression 17480) and DRM'd books can't\n * be read here, and inline images (`<img recindex>`) are dropped (we don't resolve image records). Such files\n * should be downloaded and opened in a real reader.\n */\n\nexport interface ParsedMobi {\n title: string\n html: string // the extracted book HTML (already a fragment; the viewer wraps + sandboxes it)\n}\n\n// Backward variable-width int from the last ≤4 bytes of data[0..upTo) — the trailing-entry size encoding.\nfunction trailingEntrySize(data: Uint8Array, upTo: number): number {\n let num = 0\n for (let i = Math.max(0, upTo - 4); i < upTo; i++) {\n const v = data[i]\n if (v & 0x80) num = 0\n num = (num << 7) | (v & 0x7f)\n }\n return num\n}\n\n// Total trailing bytes appended to a text record, per the MOBI \"extra data flags\".\nfunction trailingSize(data: Uint8Array, flags: number): number {\n let num = 0\n let test = flags >> 1\n while (test) {\n if (test & 1) num += trailingEntrySize(data, data.length - num)\n test >>= 1\n }\n if (flags & 1) num += (data[data.length - num - 1] & 0x3) + 1\n return num\n}\n\n// PalmDOC LZ77 decompression (compression type 2).\nfunction palmDocDecompress(data: Uint8Array): Uint8Array {\n const out: number[] = []\n let i = 0\n const n = data.length\n while (i < n) {\n const b = data[i++]\n if (b === 0) {\n out.push(0)\n } else if (b <= 8) {\n for (let j = 0; j < b && i < n; j++) out.push(data[i++]) // 1..8: copy next b literal bytes\n } else if (b <= 0x7f) {\n out.push(b) // literal byte\n } else if (b <= 0xbf) {\n // 0x80..0xBF: LZ77 back-reference (2 bytes)\n const pair = ((b << 8) | data[i++]) & 0x3fff\n const dist = pair >> 3\n const len = (pair & 7) + 3\n let pos = out.length - dist\n if (pos < 0) break\n for (let j = 0; j < len; j++) out.push(out[pos++])\n } else {\n // 0xC0..0xFF: a space followed by (byte ^ 0x80)\n out.push(0x20, b ^ 0x80)\n }\n }\n return Uint8Array.from(out)\n}\n\nfunction decodeText(bytes: Uint8Array, encoding: number): string {\n const label = encoding === 65001 ? 'utf-8' : 'windows-1252'\n try {\n return new TextDecoder(label).decode(bytes)\n } catch {\n return new TextDecoder('utf-8').decode(bytes)\n }\n}\n\nexport function parseMobi(buf: ArrayBuffer): ParsedMobi {\n const dv = new DataView(buf)\n if (buf.byteLength < 80) throw new Error('文件过小,不是有效的 MOBI')\n\n // PDB record table.\n const numRecords = dv.getUint16(76)\n if (!numRecords) throw new Error('MOBI 没有记录')\n const offsets: number[] = []\n for (let i = 0; i < numRecords; i++) offsets.push(dv.getUint32(78 + i * 8))\n offsets.push(buf.byteLength)\n const record = (i: number): Uint8Array =>\n new Uint8Array(buf, offsets[i], offsets[i + 1] - offsets[i])\n\n // Record 0: PalmDOC header (16 bytes) + MOBI header.\n const rec0 = record(0)\n const r0 = new DataView(rec0.buffer, rec0.byteOffset, rec0.byteLength)\n const compression = r0.getUint16(0)\n const textRecordCount = r0.getUint16(8)\n if (compression === 17480) {\n throw new Error('该 MOBI 使用 HUFF/CDIC 压缩,暂不支持浏览器内解析(请下载后用阅读器打开)')\n }\n\n // MOBI header fields (offsets relative to record 0).\n const hasMobiHeader =\n rec0.length > 20 && String.fromCharCode(rec0[16], rec0[17], rec0[18], rec0[19]) === 'MOBI'\n const encoding = hasMobiHeader ? r0.getUint32(28) : 1252\n const extraFlags = hasMobiHeader && rec0.length > 244 ? r0.getUint16(242) : 0\n\n // Book title from the MOBI full-name field.\n let title = ''\n if (hasMobiHeader && rec0.length >= 92) {\n const nameOff = r0.getUint32(84)\n const nameLen = r0.getUint32(88)\n if (nameOff + nameLen <= rec0.length) {\n title = decodeText(rec0.subarray(nameOff, nameOff + nameLen), encoding).trim()\n }\n }\n\n // Decompress text records 1..textRecordCount.\n const chunks: string[] = []\n const last = Math.min(textRecordCount, numRecords - 1)\n for (let i = 1; i <= last; i++) {\n let rec = record(i)\n const trail = extraFlags ? trailingSize(rec, extraFlags) : 0\n if (trail > 0 && trail < rec.length) rec = rec.subarray(0, rec.length - trail)\n const bytes = compression === 2 ? palmDocDecompress(rec) : rec\n chunks.push(decodeText(bytes, encoding))\n }\n\n let html = chunks.join('')\n if (!html.trim()) throw new Error('未能从该 MOBI 提取正文')\n // Drop image references we can't resolve (mobi <img recindex=…> → no src), to avoid broken icons.\n html = html.replace(/<img[^>]*recindex[^>]*>/gi, '')\n return { title, html }\n}\n"],"mappings":"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"}
package/dist/lib/msi.js CHANGED
@@ -330,3 +330,5 @@ function b(e) {
330
330
  }
331
331
  //#endregion
332
332
  export { e as NotMsiError, d as parseMsi };
333
+
334
+ //# sourceMappingURL=msi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msi.js","names":[],"sources":["../../src/lib/msi.ts"],"sourcesContent":["/**\n * Minimal in-browser MSI (Windows Installer) reader — no dependency, no WASM.\n *\n * An `.msi` is NOT a PE executable (that's `.exe`/`.dll` — see lib/binobj.ts), and NOT a zip (that's\n * `.appx`/`.msix` — see lib/appx.ts). It's an OLE2 **Compound File** (a.k.a. structured storage / CFBF):\n * a mini-filesystem of \"streams\" inside one file (the same container legacy `.doc`/`.xls`/`.msg` use). The\n * install metadata we surface lives in two of those streams:\n * - the standard **SummaryInformation** property set (`\\x05SummaryInformation`): title / subject / author /\n * comments, the target platform+language template, the package (revision) code, the authoring tool, dates.\n * - the **Property table** (ProductName / ProductVersion / ProductCode / UpgradeCode / Manufacturer / …),\n * spread across the MSI string pool (`_StringData` + `_StringPool`) and the `Property` table stream.\n *\n * We parse only what a \"what is this installer?\" view needs — never the embedded cabinet / payload files.\n * The logic is validated byte-for-byte against real installers using the Windows `WindowsInstaller.Installer`\n * COM automation as an oracle (the Property table + SummaryInformation match it exactly).\n *\n * Used by MsiViewer (the side viewer's MSI mode): the bytes come from the same download endpoint as any\n * other file, are parsed entirely client-side, and never leave the browser.\n */\n\nexport interface MsiMeta {\n label: string\n value: string\n}\nexport interface MsiProperty {\n name: string\n value: string\n}\n\nexport interface MsiInfo {\n /** Resolved product identity from the Property table (any field may be absent if the table is unreadable). */\n productName?: string\n productVersion?: string\n manufacturer?: string\n productCode?: string\n upgradeCode?: string\n /** Install language: a human label when the LCID is recognized (with the raw id), else the raw id. */\n language?: string\n /** Full Property table (name → value), in stored order. Empty if the table couldn't be decoded. */\n properties: MsiProperty[]\n /** SummaryInformation rows, pre-labeled (Chinese), in display order. */\n summary: MsiMeta[]\n /** Decoded names of the database tables present — a quick \"shape of the installer\" cue. */\n tables: string[]\n /** Non-fatal notes (e.g. the Property table was unreadable but SummaryInformation succeeded). */\n notes: string[]\n}\n\n/** Thrown when the bytes aren't an OLE compound file at all (so the viewer can show a clear message). */\nexport class NotMsiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'NotMsiError'\n }\n}\n\n// ── Compound File (CFBF / MS-CFB) reader ────────────────────────────────────────────────────────────\nconst CFB_SIG = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]\nconst ENDOFCHAIN = 0xfffffffe\nconst FREESECT = 0xffffffff\n\ninterface CfbEntry {\n /** Raw UTF-16 directory name (null-stripped) — MSI table names are still mangled (see decodeStreamName). */\n name: string\n /** 1 = storage, 2 = stream, 5 = root storage. */\n type: number\n start: number\n size: number\n}\n\nclass Cfb {\n private dv: DataView\n private buf: ArrayBuffer\n private sectorSize: number\n private miniSectorSize: number\n private miniCutoff: number\n private fat: number[] = []\n private miniFat: number[] = []\n private miniStream: Uint8Array = new Uint8Array(0)\n readonly entries: CfbEntry[] = []\n\n constructor(buf: ArrayBuffer) {\n this.buf = buf\n const dv = new DataView(buf)\n this.dv = dv\n if (buf.byteLength < 512) throw new NotMsiError('文件过小,不是有效的复合文件')\n for (let i = 0; i < 8; i++) {\n if (dv.getUint8(i) !== CFB_SIG[i]) {\n throw new NotMsiError('不是 OLE 复合文件(缺少 D0CF11E0 魔数)')\n }\n }\n const major = dv.getUint16(0x1a, true)\n this.sectorSize = 1 << dv.getUint16(0x1e, true)\n this.miniSectorSize = 1 << dv.getUint16(0x20, true)\n const firstDir = dv.getUint32(0x30, true)\n this.miniCutoff = dv.getUint32(0x38, true)\n const firstMiniFat = dv.getUint32(0x3c, true)\n const firstDifat = dv.getUint32(0x44, true)\n const per = this.sectorSize / 4\n\n // DIFAT (109 entries in the header, then any chained DIFAT sectors) → list of FAT sectors → FAT array.\n const difat: number[] = []\n for (let i = 0; i < 109; i++) {\n const v = dv.getUint32(0x4c + i * 4, true)\n if (v !== FREESECT && v !== ENDOFCHAIN) difat.push(v)\n }\n let ds = firstDifat\n let guard = 0\n while (ds !== ENDOFCHAIN && ds !== FREESECT && guard++ < 1_000_000) {\n const base = this.sectorOffset(ds)\n for (let i = 0; i < per - 1; i++) {\n const v = dv.getUint32(base + i * 4, true)\n if (v !== FREESECT) difat.push(v)\n }\n ds = dv.getUint32(base + (per - 1) * 4, true)\n }\n for (const fs of difat) {\n const base = this.sectorOffset(fs)\n for (let i = 0; i < per; i++) this.fat.push(dv.getUint32(base + i * 4, true))\n }\n\n // Directory: a chain of 128-byte entries starting at firstDir.\n const dirBytes = this.readFatStream(firstDir, this.chain(firstDir).length * this.sectorSize)\n const ddv = new DataView(dirBytes.buffer, dirBytes.byteOffset, dirBytes.byteLength)\n for (let o = 0; o + 128 <= dirBytes.length; o += 128) {\n const type = ddv.getUint8(o + 66)\n if (type === 0) continue // unallocated entry\n const nameLen = ddv.getUint16(o + 64, true) // bytes incl. null terminator\n let name = ''\n for (let c = 0; c + 1 < nameLen; c += 2) {\n const code = ddv.getUint16(o + c, true)\n if (code === 0) break\n name += String.fromCharCode(code)\n }\n const start = ddv.getUint32(o + 116, true)\n // v3 stores the size in 4 bytes (the high 4 may be garbage); v4 uses the full 8.\n const size =\n major <= 3 ? ddv.getUint32(o + 120, true) : Number(ddv.getBigUint64(o + 120, true))\n this.entries.push({ name, type, start, size })\n }\n\n // Mini stream (held by the root entry, in the regular FAT) + the MiniFAT (chained from firstMiniFat).\n const root = this.entries.find((e) => e.type === 5)\n if (root) this.miniStream = this.readFatStream(root.start, root.size)\n for (const s of this.chain(firstMiniFat)) {\n const base = this.sectorOffset(s)\n for (let i = 0; i < per; i++) this.miniFat.push(dv.getUint32(base + i * 4, true))\n }\n }\n\n private sectorOffset(s: number): number {\n // Sector S starts at (S+1)*sectorSize: the 512-byte header is padded to a full sector, so for v3\n // (512-byte) this is 512 + S*512, and for v4 (4096-byte) it's 4096 + S*4096 (NOT 512 + S*4096).\n return (s + 1) * this.sectorSize\n }\n /** Follow a FAT chain to a list of sector indices (bounded against corruption). */\n private chain(start: number): number[] {\n const out: number[] = []\n let s = start\n let guard = 0\n while (s !== ENDOFCHAIN && s !== FREESECT && s < this.fat.length && guard++ < 10_000_000) {\n out.push(s)\n s = this.fat[s]\n }\n return out\n }\n /** Copy one big-FAT sector, clamped to the buffer (a truncated file yields short data, not a throw). */\n private sectorBytes(s: number): Uint8Array {\n const off = this.sectorOffset(s)\n const end = Math.min(this.buf.byteLength, off + this.sectorSize)\n const out = new Uint8Array(this.sectorSize)\n if (off < this.buf.byteLength) out.set(new Uint8Array(this.buf, off, end - off))\n return out\n }\n private readFatStream(start: number, size: number): Uint8Array {\n const ch = this.chain(start)\n const out = new Uint8Array(ch.length * this.sectorSize)\n for (let i = 0; i < ch.length; i++) out.set(this.sectorBytes(ch[i]), i * this.sectorSize)\n return out.subarray(0, size)\n }\n private readMiniStream(start: number, size: number): Uint8Array {\n // The stream occupies exactly `need` mini-sectors; read only that many even if the chain runs longer\n // (some writers leave trailing/looping links past the stream end — copying them would overflow `out`).\n const need = Math.ceil(size / this.miniSectorSize)\n const out = new Uint8Array(need * this.miniSectorSize)\n let s = start\n let i = 0\n while (s !== ENDOFCHAIN && s !== FREESECT && i < need) {\n const off = s * this.miniSectorSize\n out.set(this.miniStream.subarray(off, off + this.miniSectorSize), i * this.miniSectorSize)\n i++\n s = this.miniFat[s]\n }\n return out.subarray(0, size)\n }\n /** The decompressed bytes of one directory entry's stream (small streams live in the mini stream). */\n stream(e: CfbEntry): Uint8Array {\n if (e.size === 0) return new Uint8Array(0)\n if (e.type === 5 || e.size >= this.miniCutoff) return this.readFatStream(e.start, e.size)\n return this.readMiniStream(e.start, e.size)\n }\n}\n\n// ── MSI stream-name (un)mangling ────────────────────────────────────────────────────────────────────\n// MSI encodes table/stream names into a private Unicode range using a 64-char alphabet (Wine's\n// decode_streamname). A leading 0x4840 wide-char marks \"this is a database table\".\nfunction mime2utf(x: number): string {\n if (x < 10) return String.fromCharCode(x + 48) // 0-9\n if (x < 36) return String.fromCharCode(x - 10 + 65) // A-Z\n if (x < 62) return String.fromCharCode(x - 36 + 97) // a-z\n return x === 62 ? '.' : '_'\n}\nfunction decodeStreamName(raw: string): { name: string; isTable: boolean } {\n let out = ''\n let isTable = false\n for (let i = 0; i < raw.length; i++) {\n const ch = raw.charCodeAt(i)\n if (ch >= 0x3800 && ch < 0x4800) {\n const v = ch - 0x3800 // two 6-bit characters packed into one wide-char\n out += mime2utf(v & 0x3f) + mime2utf((v >> 6) & 0x3f)\n } else if (ch >= 0x4800 && ch < 0x4840) {\n out += mime2utf(ch - 0x4800) // a single character\n } else if (ch === 0x4840) {\n isTable = true // table marker (prefix); contributes nothing to the name\n } else {\n out += String.fromCharCode(ch) // literal (ASCII names, the \\x05 property-set prefix, …)\n }\n }\n return { name: out, isTable }\n}\n\n// ── SummaryInformation (OLE property set, MS-OLEPS) ─────────────────────────────────────────────────\ninterface PropVal {\n type: number\n value: string | number\n}\n\nfunction parsePropertySet(bytes: Uint8Array): { codepage: number; props: Map<number, PropVal> } {\n const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n // 28-byte set header + one 20-byte (FMTID + offset) section locator; the section offset sits at byte 44.\n const sectionOff = v.getUint32(44, true)\n const numProps = v.getUint32(sectionOff + 4, true)\n const rows: { pid: number; abs: number }[] = []\n for (let i = 0; i < numProps; i++) {\n const pid = v.getUint32(sectionOff + 8 + i * 8, true)\n const off = v.getUint32(sectionOff + 8 + i * 8 + 4, true)\n rows.push({ pid, abs: sectionOff + off })\n }\n // The codepage (PID 1) governs how the LPSTR string properties decode — read it first.\n let codepage = 1252\n const cpRow = rows.find((r) => r.pid === 1)\n if (cpRow && v.getUint32(cpRow.abs, true) === 2) {\n let cp = v.getInt16(cpRow.abs + 4, true)\n if (cp < 0) cp += 65536 // 65001 (UTF-8) overflows a signed 16-bit read\n codepage = cp\n }\n const dec = new TextDecoder(cpLabel(codepage))\n const props = new Map<number, PropVal>()\n for (const { pid, abs } of rows) {\n const type = v.getUint32(abs, true)\n if (type === 2) props.set(pid, { type, value: v.getInt16(abs + 4, true) })\n else if (type === 3) props.set(pid, { type, value: v.getInt32(abs + 4, true) })\n else if (type === 30) {\n // LPSTR: codepage bytes, NUL-terminated — cut at the first NUL (avoids a control-char regex).\n let raw = bytes.subarray(abs + 8, abs + 8 + v.getUint32(abs + 4, true))\n const nul = raw.indexOf(0)\n if (nul >= 0) raw = raw.subarray(0, nul)\n props.set(pid, { type, value: dec.decode(raw) })\n } else if (type === 64) {\n props.set(pid, {\n type,\n value: formatFiletime(v.getUint32(abs + 4, true), v.getUint32(abs + 8, true)),\n })\n }\n }\n return { codepage, props }\n}\n\nfunction buildSummary(props: Map<number, PropVal>): MsiMeta[] {\n const out: MsiMeta[] = []\n const push = (pid: number, label: string, fmt?: (v: string | number) => string): void => {\n const p = props.get(pid)\n if (p == null) return\n const value = fmt ? fmt(p.value) : String(p.value)\n if (value) out.push({ label, value })\n }\n push(3, '主题', String) // PID_SUBJECT — usually the product/package name\n push(4, '作者 / 厂商', String) // PID_AUTHOR\n push(6, '备注', String) // PID_COMMENTS — description\n push(2, '标题', String) // PID_TITLE\n push(5, '关键字', String) // PID_KEYWORDS\n push(7, '平台 / 语言', (v) => formatTemplate(String(v))) // PID_TEMPLATE\n push(9, '包代码', String) // PID_REVNUMBER — the package (revision) code GUID\n push(18, '制作工具', String) // PID_APPNAME — authoring application\n push(12, '创建时间', String) // PID_CREATE_DTM\n push(13, '上次保存', String) // PID_LASTSAVE_DTM\n push(14, '架构版本', (v) => formatSchema(Number(v))) // PID_PAGECOUNT — min installer version\n push(15, '源类型', (v) => formatWordCount(Number(v))) // PID_WORDCOUNT — source flags\n push(19, '安全', (v) => formatSecurity(Number(v))) // PID_SECURITY\n return out\n}\n\n// ── MSI string pool + Property table ────────────────────────────────────────────────────────────────\n// `_StringPool` is an array of 4-byte slots: [length: u16][refcount: u16] (length FIRST — validated against\n// the COM oracle). Slot 0 carries the codepage (+ a long-string-refs flag in the high bit). `_StringData` is\n// every string concatenated in index order; string i lives at the running offset, `length` bytes long.\nfunction buildStringTable(\n pool: Uint8Array,\n data: Uint8Array,\n fallbackCp: number,\n): { strings: string[]; longRefs: boolean } {\n const pdv = new DataView(pool.buffer, pool.byteOffset, pool.byteLength)\n const cpRaw = pdv.getUint16(0, true) | (pdv.getUint16(2, true) << 16)\n const longRefs = (cpRaw & 0x80000000) !== 0 // ⇒ 3-byte string references in table data\n let cp = cpRaw & 0x7fffffff\n if (cp === 0) cp = fallbackCp || 1252 // codepage 0 = system ANSI; fall back to the SummaryInfo codepage\n const dec = new TextDecoder(cpLabel(cp))\n const strings: string[] = ['']\n let off = 0\n const count = Math.floor(pool.length / 4)\n for (let i = 1; i < count; i++) {\n const len = pdv.getUint16(i * 4, true)\n if (len === 0) {\n strings.push('')\n continue\n }\n strings.push(dec.decode(data.subarray(off, off + len)))\n off += len\n }\n return { strings, longRefs }\n}\n\n// The Property table is two string columns (Property name, Value) stored column-major: all the name refs,\n// then all the value refs. Each ref is a 2-byte (or 3-byte, with long string refs) index into the pool.\nfunction decodePropertyTable(\n tbl: Uint8Array,\n st: { strings: string[]; longRefs: boolean },\n): MsiProperty[] {\n const refSize = st.longRefs ? 3 : 2\n const dv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength)\n const rows = Math.floor(tbl.length / (refSize * 2))\n const ref = (idx: number): number => {\n const o = idx * refSize\n let v = dv.getUint16(o, true)\n if (refSize === 3) v += dv.getUint8(o + 2) << 16\n return v\n }\n const out: MsiProperty[] = []\n for (let r = 0; r < rows; r++) {\n const name = st.strings[ref(r)] ?? ''\n const value = st.strings[ref(rows + r)] ?? ''\n if (name) out.push({ name, value })\n }\n return out\n}\n\n// ── orchestrator ────────────────────────────────────────────────────────────────────────────────────\nexport function parseMsi(buf: ArrayBuffer): MsiInfo {\n const cfb = new Cfb(buf) // throws NotMsiError if the bytes aren't a compound file\n const decoded = cfb.entries.map((e) => ({ e, ...decodeStreamName(e.name) }))\n const notes: string[] = []\n\n const tables = decoded\n .filter((d) => d.isTable)\n .map((d) => d.name)\n .sort((a, b) => a.localeCompare(b))\n\n // SummaryInformation (standard, near-universal in MSIs).\n let summary: MsiMeta[] = []\n let siCodepage = 0\n const siD = decoded.find((d) => d.name === '\u0005SummaryInformation')\n if (siD) {\n try {\n const ps = parsePropertySet(cfb.stream(siD.e))\n siCodepage = ps.codepage\n summary = buildSummary(ps.props)\n } catch (e) {\n notes.push('SummaryInformation 解析失败:' + errMsg(e))\n }\n }\n\n // Property table (best-effort: a malformed string pool never blanks the summary above).\n let properties: MsiProperty[] = []\n const sd = decoded.find((d) => d.name === '_StringData')\n const sp = decoded.find((d) => d.name === '_StringPool')\n const pr = decoded.find((d) => d.name === 'Property')\n if (sd && sp && pr) {\n try {\n const st = buildStringTable(cfb.stream(sp.e), cfb.stream(sd.e), siCodepage)\n properties = decodePropertyTable(cfb.stream(pr.e), st)\n } catch (e) {\n notes.push('Property 表解析失败:' + errMsg(e))\n }\n }\n\n const map = new Map(properties.map((p) => [p.name, p.value]))\n const langId = map.get('ProductLanguage')\n const info: MsiInfo = {\n productName: map.get('ProductName'),\n productVersion: map.get('ProductVersion'),\n manufacturer: map.get('Manufacturer'),\n productCode: map.get('ProductCode'),\n upgradeCode: map.get('UpgradeCode'),\n language: langId ? formatLanguage(langId) : undefined,\n properties,\n summary,\n tables,\n notes,\n }\n if (!properties.length && !summary.length) {\n notes.push('未找到 MSI 摘要信息或属性表(可能是别的复合文件,而非 MSI 数据库)')\n }\n return info\n}\n\n// ── formatting helpers ──────────────────────────────────────────────────────────────────────────────\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n\nfunction cpLabel(cp: number): string {\n switch (cp) {\n case 65001:\n return 'utf-8'\n case 1200:\n return 'utf-16le'\n case 1201:\n return 'utf-16be'\n case 932:\n return 'shift_jis'\n case 936:\n return 'gbk'\n case 949:\n return 'euc-kr'\n case 950:\n return 'big5'\n case 1250:\n return 'windows-1250'\n case 1251:\n return 'windows-1251'\n case 1253:\n return 'windows-1253'\n case 1254:\n return 'windows-1254'\n case 1255:\n return 'windows-1255'\n case 1256:\n return 'windows-1256'\n case 1257:\n return 'windows-1257'\n case 1258:\n return 'windows-1258'\n default:\n return 'windows-1252' // 1252 and the system-ANSI (0) fallback\n }\n}\n\nfunction formatFiletime(lo: number, hi: number): string {\n const ft = hi * 4294967296 + lo\n if (!ft) return ''\n const ms = ft / 10000 - 11644473600000\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return ''\n const p = (n: number): string => String(n).padStart(2, '0')\n return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())} UTC`\n}\n\n// MSI \"Template\" = \"<platform>;<langid>[,<langid>…]\" e.g. \"x64;1033\". Surface the platform + language names.\nfunction formatTemplate(t: string): string {\n const [platform, langs] = t.split(';')\n const names = (langs ?? '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n .map((id) => formatLanguage(id))\n const parts: string[] = []\n if (platform && platform.trim()) parts.push(platform.trim())\n if (names.length) parts.push(names.join(', '))\n return parts.join(' · ') || t\n}\n\n// PID_PAGECOUNT for an install package = the minimum Windows Installer version (e.g. 200 ⇒ 2.00, 500 ⇒ 5.00).\nfunction formatSchema(n: number): string {\n if (!n) return ''\n return `${Math.floor(n / 100)}.${String(n % 100).padStart(2, '0')}`\n}\n\n// PID_WORDCOUNT = source flags bitfield.\nfunction formatWordCount(n: number): string {\n const flags: string[] = []\n flags.push(n & 0x2 ? '压缩 (cabinet)' : '未压缩')\n if (n & 0x1) flags.push('短文件名')\n if (n & 0x4) flags.push('管理映像')\n if (n & 0x8) flags.push('从源运行')\n return flags.join(' · ')\n}\n\nfunction formatSecurity(n: number): string {\n switch (n) {\n case 0:\n return '无限制'\n case 1:\n return '建议只读'\n case 2:\n return '强制只读'\n case 4:\n return '已锁定'\n default:\n return String(n)\n }\n}\n\n// Common Windows LCIDs → Chinese language names (best-effort; unknown ids fall back to the raw number).\nconst LCID_NAMES: Record<number, string> = {\n 0: '语言中性',\n 1025: '阿拉伯语',\n 1028: '中文(繁体)',\n 1029: '捷克语',\n 1030: '丹麦语',\n 1031: '德语',\n 1032: '希腊语',\n 1033: '英语(美国)',\n 1034: '西班牙语',\n 1035: '芬兰语',\n 1036: '法语',\n 1037: '希伯来语',\n 1038: '匈牙利语',\n 1040: '意大利语',\n 1041: '日语',\n 1042: '韩语',\n 1043: '荷兰语',\n 1044: '挪威语',\n 1045: '波兰语',\n 1046: '葡萄牙语(巴西)',\n 1049: '俄语',\n 1051: '斯洛伐克语',\n 1053: '瑞典语',\n 1054: '泰语',\n 1055: '土耳其语',\n 1057: '印尼语',\n 1058: '乌克兰语',\n 1060: '斯洛文尼亚语',\n 1066: '越南语',\n 2052: '中文(简体)',\n 2057: '英语(英国)',\n 2070: '葡萄牙语',\n 3076: '中文(香港)',\n 3082: '西班牙语(西班牙)',\n 4100: '中文(新加坡)',\n}\nfunction formatLanguage(id: string): string {\n const n = Number(id)\n const name = LCID_NAMES[n]\n return name ? `${name} (${id})` : id\n}\n"],"mappings":"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"}
@@ -18,3 +18,5 @@ function n(n) {
18
18
  }
19
19
  //#endregion
20
20
  export { t as isMissingModule, n as loadOptionalDep };
21
+
22
+ //# sourceMappingURL=optionalDep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optionalDep.js","names":[],"sources":["../../src/lib/optionalDep.ts"],"sourcesContent":["import { shallowRef, type ShallowRef } from 'vue'\n\nexport type OptionalDepStatus = 'loading' | 'ready' | 'missing' | 'error'\n\nexport interface OptionalDep<T> {\n status: ShallowRef<OptionalDepStatus>\n mod: ShallowRef<T | null>\n error: ShallowRef<unknown>\n}\n\n/**\n * Does this error mean \"the module isn't installed / couldn't be loaded\" (→ tell the user to install it),\n * as opposed to a real error thrown from INSIDE the module once it loaded? We match the bundler/browser\n * shapes for an unresolved dynamic import. Heuristic by necessity — err on \"missing\" only for these.\n *\n * Exported so viewers that `import()` their optional engine at runtime (geo/raster/psd/ebook) can decide,\n * in their own catch, whether to show the {@link MissingDependency} card vs a generic error.\n */\nexport function isMissingModule(e: unknown): boolean {\n const msg = e instanceof Error ? e.message : String(e)\n return /Failed to (fetch|resolve) dynamically imported module|Cannot find module|Importing a module script failed|ERR_MODULE_NOT_FOUND|Failed to load module/i.test(\n msg,\n )\n}\n\n/**\n * Load an OPTIONAL peer dependency at runtime (see docs/file-viewer-package-design.md §4). Because the dep is\n * `external` in the library build, it resolves from the CONSUMER's node_modules:\n * - present → `ready`, `mod` holds the module;\n * - absent → `missing` — the viewer renders a {@link MissingDependency} card telling the user to install it;\n * - throws → `error` (a genuine failure inside the module after it loaded).\n *\n * Usage: `const dep = loadOptionalDep(() => import('pdfjs-dist'))`, then branch on `dep.status.value`.\n */\nexport function loadOptionalDep<T = unknown>(importer: () => Promise<T>): OptionalDep<T> {\n const status = shallowRef<OptionalDepStatus>('loading')\n const mod = shallowRef<T | null>(null)\n const error = shallowRef<unknown>(null)\n importer().then(\n (m) => {\n mod.value = m\n status.value = 'ready'\n },\n (e) => {\n error.value = e\n status.value = isMissingModule(e) ? 'missing' : 'error'\n },\n )\n return { status, mod, error }\n}\n"],"mappings":";;AAkBA,SAAgB,EAAgB,GAAqB;CACnD,IAAM,IAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;CACrD,OAAO,wJAAwJ,KAC7J,CACF;AACF;AAWA,SAAgB,EAA6B,GAA4C;CACvF,IAAM,IAAS,EAA8B,SAAS,GAChD,IAAM,EAAqB,IAAI,GAC/B,IAAQ,EAAoB,IAAI;CAWtC,OAVA,EAAS,CAAC,CAAC,MACR,MAAM;EAEL,AADA,EAAI,QAAQ,GACZ,EAAO,QAAQ;CACjB,IACC,MAAM;EAEL,AADA,EAAM,QAAQ,GACd,EAAO,QAAQ,EAAgB,CAAC,IAAI,YAAY;CAClD,CACF,GACO;EAAE;EAAQ;EAAK;CAAM;AAC9B"}
@@ -0,0 +1,11 @@
1
+ import type { PDFDocumentProxy } from 'pdfjs-dist';
2
+ export interface PdfNavigationItem {
3
+ id: string;
4
+ title: string;
5
+ level: number;
6
+ pageNumber: number | null;
7
+ }
8
+ export declare function loadPdfNavigation(document: PDFDocumentProxy): Promise<{
9
+ outline: PdfNavigationItem[];
10
+ pageLabels: string[];
11
+ }>;
@@ -0,0 +1,32 @@
1
+ //#region src/lib/pdfNavigation.ts
2
+ async function e(e, t) {
3
+ if (!t) return null;
4
+ try {
5
+ let n = (typeof t == "string" ? await e.getDestination(t) : t)?.[0];
6
+ return !n || typeof n == "number" ? typeof n == "number" ? n + 1 : null : await e.getPageIndex(n) + 1;
7
+ } catch {
8
+ return null;
9
+ }
10
+ }
11
+ async function t(n, r, i = 0, a = "root") {
12
+ return (await Promise.all(r.map(async (r, o) => {
13
+ let s = `${a}-${o}`;
14
+ return [{
15
+ id: `pdf-outline-${s}`,
16
+ title: r.title.trim() || "未命名书签",
17
+ level: i,
18
+ pageNumber: await e(n, r.dest)
19
+ }, ...await t(n, r.items ?? [], i + 1, s)];
20
+ }))).flat();
21
+ }
22
+ async function n(e) {
23
+ let [n, r] = await Promise.all([e.getOutline().then((n) => t(e, n ?? [])).catch(() => []), e.getPageLabels().catch(() => null)]);
24
+ return {
25
+ outline: n,
26
+ pageLabels: r ?? []
27
+ };
28
+ }
29
+ //#endregion
30
+ export { n as loadPdfNavigation };
31
+
32
+ //# sourceMappingURL=pdfNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdfNavigation.js","names":[],"sources":["../../src/lib/pdfNavigation.ts"],"sourcesContent":["import type { PDFDocumentProxy } from 'pdfjs-dist'\n\nexport interface PdfNavigationItem {\n id: string\n title: string\n level: number\n pageNumber: number | null\n}\n\ntype PdfOutline = Awaited<ReturnType<PDFDocumentProxy['getOutline']>>\ntype PdfOutlineItem = NonNullable<PdfOutline>[number]\ntype PdfPageReference = Parameters<PDFDocumentProxy['getPageIndex']>[0]\n\nasync function resolvePageNumber(\n document: PDFDocumentProxy,\n destination: PdfOutlineItem['dest'],\n): Promise<number | null> {\n if (!destination) return null\n\n try {\n const resolved =\n typeof destination === 'string' ? await document.getDestination(destination) : destination\n const pageReference = resolved?.[0]\n if (!pageReference || typeof pageReference === 'number') {\n return typeof pageReference === 'number' ? pageReference + 1 : null\n }\n return (await document.getPageIndex(pageReference as PdfPageReference)) + 1\n } catch {\n return null\n }\n}\n\nasync function flattenOutline(\n document: PDFDocumentProxy,\n items: readonly PdfOutlineItem[],\n level = 0,\n parentPath = 'root',\n): Promise<PdfNavigationItem[]> {\n const groups = await Promise.all(\n items.map(async (item, index) => {\n const path = `${parentPath}-${index}`\n const current: PdfNavigationItem = {\n id: `pdf-outline-${path}`,\n title: item.title.trim() || '未命名书签',\n level,\n pageNumber: await resolvePageNumber(document, item.dest),\n }\n const children = await flattenOutline(document, item.items ?? [], level + 1, path)\n return [current, ...children]\n }),\n )\n return groups.flat()\n}\n\nexport async function loadPdfNavigation(document: PDFDocumentProxy): Promise<{\n outline: PdfNavigationItem[]\n pageLabels: string[]\n}> {\n const [outline, pageLabels] = await Promise.all([\n document\n .getOutline()\n .then((items) => flattenOutline(document, items ?? []))\n .catch(() => []),\n document.getPageLabels().catch(() => null),\n ])\n return {\n outline,\n pageLabels: pageLabels ?? [],\n }\n}\n"],"mappings":";AAaA,eAAe,EACb,GACA,GACwB;CACxB,IAAI,CAAC,GAAa,OAAO;CAEzB,IAAI;EAGF,IAAM,KADJ,OAAO,KAAgB,WAAW,MAAM,EAAS,eAAe,CAAW,IAAI,EAAA,GAChD;EAIjC,OAHI,CAAC,KAAiB,OAAO,KAAkB,WACtC,OAAO,KAAkB,WAAW,IAAgB,IAAI,OAEzD,MAAM,EAAS,aAAa,CAAiC,IAAK;CAC5E,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAe,EACb,GACA,GACA,IAAQ,GACR,IAAa,QACiB;CAc9B,QAAO,MAbc,QAAQ,IAC3B,EAAM,IAAI,OAAO,GAAM,MAAU;EAC/B,IAAM,IAAO,GAAG,EAAW,GAAG;EAQ9B,OAAO,CAAC;GANN,IAAI,eAAe;GACnB,OAAO,EAAK,MAAM,KAAK,KAAK;GAC5B;GACA,YAAY,MAAM,EAAkB,GAAU,EAAK,IAAI;EAGjD,GAAS,GAAG,MADG,EAAe,GAAU,EAAK,SAAS,CAAC,GAAG,IAAQ,GAAG,CAAI,CACrD;CAC9B,CAAC,CACH,EAAA,CACc,KAAK;AACrB;AAEA,eAAsB,EAAkB,GAGrC;CACD,IAAM,CAAC,GAAS,KAAc,MAAM,QAAQ,IAAI,CAC9C,EACG,WAAW,CAAC,CACZ,MAAM,MAAU,EAAe,GAAU,KAAS,CAAC,CAAC,CAAC,CAAC,CACtD,YAAY,CAAC,CAAC,GACjB,EAAS,cAAc,CAAC,CAAC,YAAY,IAAI,CAC3C,CAAC;CACD,OAAO;EACL;EACA,YAAY,KAAc,CAAC;CAC7B;AACF"}
@@ -354,3 +354,5 @@ function X(e) {
354
354
  }
355
355
  //#endregion
356
356
  export { K as looksLikePkcs12, Y as readPkcs12 };
357
+
358
+ //# sourceMappingURL=pkcs12.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkcs12.js","names":[],"sources":["../../src/lib/pkcs12.ts"],"sourcesContent":["/**\n * Zero-dependency PKCS#12 (PFX) reader — for the keystore viewer (JksViewer.vue), so `.p12`/`.pfx` and the very\n * common `.jks`-that-is-actually-PKCS#12 (keytool defaults to PKCS12 since JDK 9) open with their certificates\n * and private keys instead of just an opaque blob.\n *\n * PKCS#12 (RFC 7292) is a PKCS#7 container whose bags are ALL encrypted (unlike JKS, where certs are plaintext),\n * so nothing shows without the password. This module parses the PFX / AuthenticatedSafe / SafeBag structure,\n * verifies the integrity MAC (which doubles as the password check), and decrypts the bags:\n * - legacy PBE1 (PKCS#12 KDF, SHA-1): `pbeWithSHA1And3-KeyTripleDES` (3DES, see lib/des.ts),\n * `pbeWithSHA1And{40,128}BitRC2` (RC2, see lib/rc2.ts), and the RC4 variants;\n * - modern PBES2: PBKDF2 (HMAC-SHA1/SHA256) + AES-CBC (see lib/aes.ts) or 3DES.\n * The MAC digest supports SHA-1 / SHA-256. Anything outside this set is reported (not decrypted) rather than\n * failing the whole file. READ-ONLY: no signature/trust verification. WebCrypto ships no 3DES/RC2, hence the\n * hand-rolled ciphers.\n */\n\nimport { decodeAsn1, oidToString, TAG, type Asn1Node } from './asn1'\nimport { describePrivateKey } from './x509'\nimport { Sha1 } from './sha1'\nimport { sha256 } from './sha256'\nimport { tripleDesCbcDecrypt } from './des'\nimport { rc2CbcDecrypt } from './rc2'\nimport { aesCbcDecrypt } from './aes'\n\n// ── OIDs ──────────────────────────────────────────────────────────────────────────────────────────\nconst PKCS7_DATA = '1.2.840.113549.1.7.1'\nconst PKCS7_SIGNED_DATA = '1.2.840.113549.1.7.2'\nconst PKCS7_ENCRYPTED_DATA = '1.2.840.113549.1.7.6'\nconst CERT_BAG = '1.2.840.113549.1.12.10.1.3'\nconst KEY_BAG = '1.2.840.113549.1.12.10.1.1'\nconst SHROUDED_KEY_BAG = '1.2.840.113549.1.12.10.1.2'\nconst X509_CERT = '1.2.840.113549.1.9.22.1'\nconst ATTR_FRIENDLY_NAME = '1.2.840.113549.1.9.20'\nconst ATTR_LOCAL_KEY_ID = '1.2.840.113549.1.9.21'\nconst PBES2 = '1.2.840.113549.1.5.13'\nconst PBKDF2 = '1.2.840.113549.1.5.12'\nconst DES_EDE3_CBC = '1.2.840.113549.3.7'\nconst HMAC_SHA1 = '1.2.840.113549.2.7'\nconst HMAC_SHA256 = '1.2.840.113549.2.9'\nconst OID_SHA1 = '1.3.14.3.2.26'\nconst OID_SHA256 = '2.16.840.1.101.3.4.2.1'\nconst AES_CBC: Record<string, number> = {\n '2.16.840.1.101.3.4.1.2': 16, // AES-128-CBC\n '2.16.840.1.101.3.4.1.22': 24, // AES-192-CBC\n '2.16.840.1.101.3.4.1.42': 32, // AES-256-CBC\n}\n// PBE1 (PKCS#12 KDF) schemes → key length, IV length (0 = stream cipher RC4), RC2 effective bits, cipher tag.\ninterface Pbe1 {\n keyLen: number\n ivLen: number\n effBits?: number\n cipher: '3des' | 'rc2' | 'rc4'\n}\nconst PBE1: Record<string, Pbe1> = {\n '1.2.840.113549.1.12.1.1': { keyLen: 16, ivLen: 0, cipher: 'rc4' },\n '1.2.840.113549.1.12.1.2': { keyLen: 5, ivLen: 0, cipher: 'rc4' },\n '1.2.840.113549.1.12.1.3': { keyLen: 24, ivLen: 8, cipher: '3des' },\n '1.2.840.113549.1.12.1.4': { keyLen: 16, ivLen: 8, cipher: '3des' },\n '1.2.840.113549.1.12.1.5': { keyLen: 16, ivLen: 8, effBits: 128, cipher: 'rc2' },\n '1.2.840.113549.1.12.1.6': { keyLen: 5, ivLen: 8, effBits: 40, cipher: 'rc2' },\n}\nconst PBE_NAMES: Record<string, string> = {\n '1.2.840.113549.1.12.1.1': 'PBE-SHA1-RC4-128',\n '1.2.840.113549.1.12.1.2': 'PBE-SHA1-RC4-40',\n '1.2.840.113549.1.12.1.3': 'PBE-SHA1-3DES',\n '1.2.840.113549.1.12.1.4': 'PBE-SHA1-2DES',\n '1.2.840.113549.1.12.1.5': 'PBE-SHA1-RC2-128',\n '1.2.840.113549.1.12.1.6': 'PBE-SHA1-RC2-40',\n [PBES2]: 'PBES2',\n}\n\n// ── small byte helpers ──────────────────────────────────────────────────────────────────────────\nfunction concat(...arrs: Uint8Array[]): Uint8Array {\n let n = 0\n for (const a of arrs) n += a.length\n const out = new Uint8Array(n)\n let p = 0\n for (const a of arrs) {\n out.set(a, p)\n p += a.length\n }\n return out\n}\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n return true\n}\nfunction intValue(node: Asn1Node): number {\n let v = 0\n for (const b of node.content) v = v * 256 + b\n return v\n}\nfunction bytesToHex(b: Uint8Array): string {\n let s = ''\n for (const x of b) s += x.toString(16).padStart(2, '0')\n return s\n}\n\n// ── hashes / HMAC / KDFs ─────────────────────────────────────────────────────────────────────────\ninterface HashSpec {\n u: number // output bytes\n v: number // block bytes\n hash: (x: Uint8Array) => Uint8Array\n}\nconst SHA1: HashSpec = { u: 20, v: 64, hash: (x) => new Sha1().update(x).digest() }\nconst SHA256: HashSpec = { u: 32, v: 64, hash: (x) => sha256(x) }\n\nfunction hmac(spec: HashSpec, key: Uint8Array, msg: Uint8Array): Uint8Array {\n let k = key.length > spec.v ? spec.hash(key) : key\n const ipad = new Uint8Array(spec.v)\n const opad = new Uint8Array(spec.v)\n ipad.set(k)\n opad.set(k)\n for (let i = 0; i < spec.v; i++) {\n ipad[i] ^= 0x36\n opad[i] ^= 0x5c\n }\n return spec.hash(concat(opad, spec.hash(concat(ipad, msg))))\n}\n\nfunction pbkdf2(\n spec: HashSpec,\n pw: Uint8Array,\n salt: Uint8Array,\n iter: number,\n dkLen: number,\n): Uint8Array {\n const out = new Uint8Array(Math.ceil(dkLen / spec.u) * spec.u)\n const blocks = out.length / spec.u\n for (let i = 1; i <= blocks; i++) {\n const idx = new Uint8Array([(i >>> 24) & 0xff, (i >>> 16) & 0xff, (i >>> 8) & 0xff, i & 0xff])\n let u = hmac(spec, pw, concat(salt, idx))\n const t = u.slice()\n for (let it = 1; it < iter; it++) {\n u = hmac(spec, pw, u)\n for (let k = 0; k < spec.u; k++) t[k] ^= u[k]\n }\n out.set(t, (i - 1) * spec.u)\n }\n return out.subarray(0, dkLen)\n}\n\n/** Repeat `src` cyclically to a length that is a multiple of `v` (empty stays empty). */\nfunction fillToBlock(src: Uint8Array, v: number): Uint8Array {\n if (src.length === 0) return new Uint8Array(0)\n const len = v * Math.ceil(src.length / v)\n const out = new Uint8Array(len)\n for (let i = 0; i < len; i++) out[i] = src[i % src.length]\n return out\n}\n\n/** The PKCS#12 key-derivation function (RFC 7292 Appendix B.2). `id`: 1=key, 2=IV, 3=MAC. */\nfunction pkcs12Kdf(\n spec: HashSpec,\n pw: Uint8Array,\n salt: Uint8Array,\n iter: number,\n id: number,\n n: number,\n): Uint8Array {\n const { u, v } = spec\n const D = new Uint8Array(v).fill(id)\n const I = concat(fillToBlock(salt, v), fillToBlock(pw, v))\n const out = new Uint8Array(n)\n let pos = 0\n while (pos < n) {\n let A = spec.hash(concat(D, I))\n for (let it = 1; it < iter; it++) A = spec.hash(A)\n out.set(A.subarray(0, Math.min(u, n - pos)), pos)\n pos += u\n if (pos < n) {\n const B = fillToBlock(A, v) // v bytes (A is ≤ v)\n for (let b = 0; b < I.length; b += v) {\n let carry = 1\n for (let k = v - 1; k >= 0; k--) {\n const sum = I[b + k] + B[k] + carry\n I[b + k] = sum & 0xff\n carry = sum >> 8\n }\n }\n }\n }\n return out\n}\n\n/** Password → BMPString bytes (UTF-16BE + a trailing U+0000), the form the PKCS#12 KDF hashes. */\nfunction bmpPassword(password: string): Uint8Array {\n const out = new Uint8Array(password.length * 2 + 2)\n for (let i = 0; i < password.length; i++) {\n const c = password.charCodeAt(i)\n out[2 * i] = (c >>> 8) & 0xff\n out[2 * i + 1] = c & 0xff\n }\n return out // last two bytes stay 0 (the terminator)\n}\n\nfunction rc4(key: Uint8Array, data: Uint8Array): Uint8Array {\n const s = new Uint8Array(256)\n for (let i = 0; i < 256; i++) s[i] = i\n let j = 0\n for (let i = 0; i < 256; i++) {\n j = (j + s[i] + key[i % key.length]) & 0xff\n const t = s[i]\n s[i] = s[j]\n s[j] = t\n }\n const out = new Uint8Array(data.length)\n let a = 0\n let b = 0\n for (let k = 0; k < data.length; k++) {\n a = (a + 1) & 0xff\n b = (b + s[a]) & 0xff\n const t = s[a]\n s[a] = s[b]\n s[b] = t\n out[k] = data[k] ^ s[(s[a] + s[b]) & 0xff]\n }\n return out\n}\n\n/** Strip PKCS#7 padding for a given block size; null if the padding is invalid (⇒ wrong password). */\nfunction pkcs7Unpad(data: Uint8Array, blockSize: number): Uint8Array | null {\n if (data.length === 0 || data.length % blockSize !== 0) return null\n const p = data[data.length - 1]\n if (p < 1 || p > blockSize) return null\n for (let i = data.length - p; i < data.length; i++) if (data[i] !== p) return null\n return data.subarray(0, data.length - p)\n}\n\nclass Pkcs12Unsupported extends Error {}\n\nfunction oidOf(algId: Asn1Node): string {\n return oidToString(algId.children[0].content)\n}\n\n// ── ASN.1 navigation helpers ─────────────────────────────────────────────────────────────────────\n/** A `[n] EXPLICIT` wrapper's single inner value. */\nfunction explicit(node: Asn1Node): Asn1Node {\n return node.children.length ? node.children[0] : decodeAsn1(node.content)[0]\n}\n/** The bytes of an OCTET STRING (primitive → content; BER-constructed → concatenated segments). */\nfunction octetContent(node: Asn1Node): Uint8Array {\n if (!node.constructed) return node.content\n return concat(...node.children.map((c) => octetContent(c)))\n}\n\n/**\n * Decrypt one PBE-encrypted blob (an encryptedData content, or a shrouded key bag), stripping PKCS#7 padding.\n * Returns null on invalid padding (wrong password); throws {@link Pkcs12Unsupported} for an algorithm we don't\n * implement. Handles legacy PBE1 (PKCS#12 KDF) and modern PBES2 (PBKDF2 + AES/3DES).\n */\nfunction decryptPbe(algId: Asn1Node, ct: Uint8Array, password: string): Uint8Array | null {\n const oid = oidOf(algId)\n const params = algId.children[1]\n\n const pbe1 = PBE1[oid]\n if (pbe1) {\n const salt = params.children[0].content\n const iter = intValue(params.children[1])\n const bmp = bmpPassword(password)\n const key = pkcs12Kdf(SHA1, bmp, salt, iter, 1, pbe1.keyLen)\n if (pbe1.cipher === 'rc4') return rc4(key, ct) // stream cipher: no padding\n const iv = pkcs12Kdf(SHA1, bmp, salt, iter, 2, pbe1.ivLen)\n const raw =\n pbe1.cipher === '3des'\n ? tripleDesCbcDecrypt(key, iv, ct)\n : rc2CbcDecrypt(key, iv, ct, pbe1.effBits)\n return pkcs7Unpad(raw, 8)\n }\n\n if (oid === PBES2) {\n // PBES2-params ::= SEQUENCE { keyDerivationFunc AlgorithmIdentifier, encryptionScheme AlgorithmIdentifier }\n const kdf = params.children[0]\n if (oidOf(kdf) !== PBKDF2) throw new Pkcs12Unsupported('PBES2 KDF ' + oidOf(kdf))\n const kdfParams = kdf.children[1]\n const salt = kdfParams.children[0].content\n const iter = intValue(kdfParams.children[1])\n let keyLenHint = 0\n let prf: HashSpec = SHA1\n for (let i = 2; i < kdfParams.children.length; i++) {\n const c = kdfParams.children[i]\n if (c.tagNumber === TAG.INTEGER) keyLenHint = intValue(c)\n else if (c.tagNumber === TAG.SEQUENCE) {\n const p = oidToString(c.children[0].content)\n prf =\n p === HMAC_SHA256\n ? SHA256\n : p === HMAC_SHA1\n ? SHA1\n : (() => {\n throw new Pkcs12Unsupported('PBKDF2 PRF ' + p)\n })()\n }\n }\n const enc = params.children[1]\n const encOid = oidOf(enc)\n const encParams = enc.children[1]\n if (AES_CBC[encOid]) {\n const keyLen = AES_CBC[encOid]\n const iv = encParams.content\n const key = pbkdf2(prf, new TextEncoder().encode(password), salt, iter, keyLenHint || keyLen)\n return pkcs7Unpad(aesCbcDecrypt(key, iv, ct), 16)\n }\n if (encOid === DES_EDE3_CBC) {\n const iv = encParams.content\n const key = pbkdf2(prf, new TextEncoder().encode(password), salt, iter, keyLenHint || 24)\n return pkcs7Unpad(tripleDesCbcDecrypt(key, iv, ct), 8)\n }\n throw new Pkcs12Unsupported('PBES2 cipher ' + encOid)\n }\n\n throw new Pkcs12Unsupported(PBE_NAMES[oid] ?? oid)\n}\n\n// ── public API ────────────────────────────────────────────────────────────────────────────────────\nexport interface P12Cert {\n der: Uint8Array\n friendlyName?: string\n localKeyId?: string\n}\nexport interface P12Key {\n pkcs8: Uint8Array\n algorithm: string\n bits?: number\n curve?: string\n friendlyName?: string\n localKeyId?: string\n}\nexport interface Pkcs12Result {\n macPresent: boolean\n /** true = MAC verified (password correct); false→never returned (becomes wrong-password); null = no/unsupported MAC. */\n macVerified: boolean | null\n macAlgorithm?: string\n certs: P12Cert[]\n keys: P12Key[]\n /** Human names of the PBE algorithms encountered (for display). */\n encryptionAlgos: string[]\n /** Non-fatal notes (e.g. a bag encrypted with an unsupported algorithm was skipped). */\n warnings: string[]\n}\nexport type Pkcs12Open =\n | { ok: true; result: Pkcs12Result }\n | { ok: false; reason: 'wrong-password' | 'unsupported' | 'malformed'; detail?: string }\n\n/** Does this look like a PKCS#12 PFX (SEQUENCE { version 3, ContentInfo … })? Cheap structural sniff. */\nexport function looksLikePkcs12(bytes: Uint8Array): boolean {\n try {\n const pfx = decodeAsn1(bytes)[0]\n if (!pfx || pfx.tagNumber !== TAG.SEQUENCE) return false\n const ver = pfx.children[0]\n if (!ver || ver.tagNumber !== TAG.INTEGER || intValue(ver) !== 3) return false\n const t = oidToString(pfx.children[1].children[0].content)\n return t === PKCS7_DATA || t === PKCS7_SIGNED_DATA\n } catch {\n return false\n }\n}\n\nfunction digestName(oid: string): string {\n return oid === OID_SHA1 ? 'HMAC-SHA1' : oid === OID_SHA256 ? 'HMAC-SHA256' : oid\n}\n\nfunction parseAttrs(setNode: Asn1Node | undefined): { friendlyName?: string; localKeyId?: string } {\n const out: { friendlyName?: string; localKeyId?: string } = {}\n if (!setNode) return out\n for (const attr of setNode.children) {\n const id = oidToString(attr.children[0].content)\n const val = attr.children[1]?.children[0]\n if (!val) continue\n if (id === ATTR_FRIENDLY_NAME) {\n try {\n out.friendlyName = new TextDecoder('utf-16be').decode(val.content)\n } catch {\n /* leave unset */\n }\n } else if (id === ATTR_LOCAL_KEY_ID) {\n out.localKeyId = bytesToHex(val.content)\n }\n }\n return out\n}\n\n/**\n * Parse + decrypt a PKCS#12 keystore with `password`. Certificates and private keys come back decrypted; the\n * MAC (when SHA-1/SHA-256) is verified and doubles as the password check. Returns a structured error for a\n * wrong password / unsupported algorithm / malformed file rather than throwing.\n */\nexport function readPkcs12(buf: ArrayBuffer, password: string): Pkcs12Open {\n try {\n const bytes = new Uint8Array(buf)\n const pfx = decodeAsn1(bytes)[0]\n if (!pfx || pfx.tagNumber !== TAG.SEQUENCE) return { ok: false, reason: 'malformed' }\n const authSafe = pfx.children[1]\n if (!authSafe || oidToString(authSafe.children[0].content) !== PKCS7_DATA) {\n return {\n ok: false,\n reason: 'unsupported',\n detail: '仅支持口令完整性(pkcs7-data)的 PKCS#12',\n }\n }\n const authContent = octetContent(explicit(authSafe.children[1])) // AuthenticatedSafe DER = MAC message\n\n // MAC (integrity + password check)\n let macPresent = false\n let macVerified: boolean | null = null\n let macAlgorithm: string | undefined\n if (pfx.children.length >= 3) {\n macPresent = true\n const macData = pfx.children[2]\n const digestInfo = macData.children[0]\n const digestAlgOid = oidToString(digestInfo.children[0].children[0].content)\n const storedMac = digestInfo.children[1].content\n const macSalt = macData.children[1].content\n const macIter = macData.children[2] ? intValue(macData.children[2]) : 1\n macAlgorithm = digestName(digestAlgOid)\n const spec = digestAlgOid === OID_SHA1 ? SHA1 : digestAlgOid === OID_SHA256 ? SHA256 : null\n if (spec) {\n const key = pkcs12Kdf(spec, bmpPassword(password), macSalt, macIter, 3, spec.u)\n if (!bytesEqual(hmac(spec, key, authContent), storedMac)) {\n return { ok: false, reason: 'wrong-password' }\n }\n macVerified = true\n }\n }\n\n const certs: P12Cert[] = []\n const keys: P12Key[] = []\n const encryptionAlgos = new Set<string>()\n const warnings: string[] = []\n let sawWrongPw = false\n\n const processBags = (bagNodes: Asn1Node[]): void => {\n for (const bag of bagNodes) {\n const bagId = oidToString(bag.children[0].content)\n const inner = explicit(bag.children[1])\n const attrs = parseAttrs(bag.children[2])\n if (bagId === CERT_BAG) {\n if (oidToString(inner.children[0].content) === X509_CERT) {\n certs.push({ der: octetContent(explicit(inner.children[1])).slice(), ...attrs })\n }\n } else if (bagId === KEY_BAG) {\n const pkcs8 = nodeTlv(inner)\n keys.push({ pkcs8, ...describePrivateKey(pkcs8), ...attrs })\n } else if (bagId === SHROUDED_KEY_BAG) {\n const algId = inner.children[0]\n encryptionAlgos.add(PBE_NAMES[oidOf(algId)] ?? oidOf(algId))\n let pk: Uint8Array | null\n try {\n pk = decryptPbe(algId, inner.children[1].content, password)\n } catch (e) {\n warnings.push(`私钥加密方式不支持:${e instanceof Error ? e.message : String(e)}`)\n continue\n }\n if (!pk) {\n sawWrongPw = true\n continue\n }\n keys.push({ pkcs8: pk.slice(), ...describePrivateKey(pk), ...attrs })\n }\n }\n }\n\n const authSafeSeq = decodeAsn1(authContent)[0]\n for (const ci of authSafeSeq.children) {\n const ciType = oidToString(ci.children[0].content)\n if (ciType === PKCS7_DATA) {\n const safe = decodeAsn1(octetContent(explicit(ci.children[1])))[0]\n if (safe) processBags(safe.children)\n } else if (ciType === PKCS7_ENCRYPTED_DATA) {\n // EncryptedData ::= SEQUENCE { version, EncryptedContentInfo { contentType, algId, [0] IMPLICIT OCTET STRING } }\n const eci = explicit(ci.children[1]).children[1]\n const algId = eci.children[1]\n encryptionAlgos.add(PBE_NAMES[oidOf(algId)] ?? oidOf(algId))\n const ctNode = eci.children[2]\n const ct = ctNode.constructed ? octetContent(ctNode) : ctNode.content\n let pt: Uint8Array | null\n try {\n pt = decryptPbe(algId, ct, password)\n } catch (e) {\n warnings.push(`证书加密方式不支持:${e instanceof Error ? e.message : String(e)}`)\n continue\n }\n if (!pt) {\n sawWrongPw = true\n continue\n }\n const safe = decodeAsn1(pt)[0]\n if (safe) processBags(safe.children)\n }\n }\n\n // A decrypt that produced invalid padding, with nothing recovered, means the password was wrong (when the\n // MAC wasn't available as the definitive check).\n if (sawWrongPw && !certs.length && !keys.length && macVerified !== true) {\n return { ok: false, reason: 'wrong-password' }\n }\n return {\n ok: true,\n result: {\n macPresent,\n macVerified,\n macAlgorithm,\n certs,\n keys,\n encryptionAlgos: [...encryptionAlgos],\n warnings,\n },\n }\n } catch (e) {\n return { ok: false, reason: 'malformed', detail: e instanceof Error ? e.message : String(e) }\n }\n}\n\n/** Re-encode a decoded node as its full DER TLV (definite length, tag number < 31 — true for our bag values). */\nfunction nodeTlv(node: Asn1Node): Uint8Array {\n const first = (node.tagClass << 6) | (node.constructed ? 0x20 : 0) | node.tagNumber\n const n = node.content.length\n const lenBytes: number[] = n < 0x80 ? [n] : []\n if (n >= 0x80) {\n const tmp: number[] = []\n let x = n\n while (x > 0) {\n tmp.unshift(x & 0xff)\n x >>= 8\n }\n lenBytes.push(0x80 | tmp.length, ...tmp)\n }\n return concat(new Uint8Array([first, ...lenBytes]), node.content)\n}\n"],"mappings":"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"}
@@ -25,3 +25,5 @@ function r(r) {
25
25
  }
26
26
  //#endregion
27
27
  export { r as buildPptxNavigation };
28
+
29
+ //# sourceMappingURL=pptxNavigation.js.map