omni-viewer-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/THIRD_PARTY_NOTICES.md +49 -0
  4. package/dist/assets/audio-engine/audio_engine.mjs +2 -0
  5. package/dist/assets/audio-engine/audio_engine.wasm +0 -0
  6. package/dist/assets/pdfjs/pdf.worker.min.mjs +21 -0
  7. package/dist/host/index.d.ts +133 -0
  8. package/dist/host/index.js +10 -0
  9. package/dist/i18n/catalog.en.d.ts +1 -0
  10. package/dist/i18n/catalog.en.js +411 -0
  11. package/dist/i18n/catalog.ko.d.ts +1 -0
  12. package/dist/i18n/catalog.ko.js +68 -0
  13. package/dist/i18n/index.d.ts +18 -0
  14. package/dist/i18n/index.js +41 -0
  15. package/dist/licenses/emscripten.txt +101 -0
  16. package/dist/licenses/kissfft.txt +28 -0
  17. package/dist/licenses/pdfjs-dist.txt +177 -0
  18. package/dist/parsers/a2l/index.d.ts +1 -0
  19. package/dist/parsers/a2l/index.js +1 -0
  20. package/dist/parsers/archive/index.d.ts +22 -0
  21. package/dist/parsers/archive/index.js +46 -0
  22. package/dist/parsers/archive/model.d.ts +29 -0
  23. package/dist/parsers/archive/model.js +1 -0
  24. package/dist/parsers/archive/worker.d.ts +21 -0
  25. package/dist/parsers/archive/worker.js +1 -0
  26. package/dist/parsers/arxml/index.d.ts +1 -0
  27. package/dist/parsers/arxml/index.js +1 -0
  28. package/dist/parsers/asc/index.d.ts +1 -0
  29. package/dist/parsers/asc/index.js +1 -0
  30. package/dist/parsers/audio/index.d.ts +9 -0
  31. package/dist/parsers/audio/index.js +46 -0
  32. package/dist/parsers/automotive/index.d.ts +33 -0
  33. package/dist/parsers/automotive/index.js +973 -0
  34. package/dist/parsers/blf/index.d.ts +1 -0
  35. package/dist/parsers/blf/index.js +1 -0
  36. package/dist/parsers/csv/delimiter.d.ts +31 -0
  37. package/dist/parsers/csv/delimiter.js +151 -0
  38. package/dist/parsers/csv/index.d.ts +30 -0
  39. package/dist/parsers/csv/index.js +108 -0
  40. package/dist/parsers/csv/parseText.d.ts +20 -0
  41. package/dist/parsers/csv/parseText.js +108 -0
  42. package/dist/parsers/csv/sort.d.ts +26 -0
  43. package/dist/parsers/csv/sort.js +224 -0
  44. package/dist/parsers/csv/statistics.d.ts +49 -0
  45. package/dist/parsers/csv/statistics.js +150 -0
  46. package/dist/parsers/dbc/index.d.ts +56 -0
  47. package/dist/parsers/dbc/index.js +94 -0
  48. package/dist/parsers/doc-binary/index.d.ts +35 -0
  49. package/dist/parsers/doc-binary/index.js +267 -0
  50. package/dist/parsers/doc-binary/vscode-parser.d.ts +142 -0
  51. package/dist/parsers/doc-binary/vscode-parser.js +3747 -0
  52. package/dist/parsers/excel/index.d.ts +17 -0
  53. package/dist/parsers/excel/index.js +406 -0
  54. package/dist/parsers/excel/model.d.ts +80 -0
  55. package/dist/parsers/excel/model.js +48 -0
  56. package/dist/parsers/excel/serialize.d.ts +3 -0
  57. package/dist/parsers/excel/serialize.js +78 -0
  58. package/dist/parsers/hdf5/index.d.ts +75 -0
  59. package/dist/parsers/hdf5/index.js +658 -0
  60. package/dist/parsers/hdf5/node.d.ts +21 -0
  61. package/dist/parsers/hdf5/node.js +95 -0
  62. package/dist/parsers/json/index.d.ts +15 -0
  63. package/dist/parsers/json/index.js +102 -0
  64. package/dist/parsers/json/model.d.ts +42 -0
  65. package/dist/parsers/json/model.js +140 -0
  66. package/dist/parsers/json/parse.d.ts +22 -0
  67. package/dist/parsers/json/parse.js +279 -0
  68. package/dist/parsers/json/tokenizer.d.ts +17 -0
  69. package/dist/parsers/json/tokenizer.js +175 -0
  70. package/dist/parsers/jsonl/index.d.ts +14 -0
  71. package/dist/parsers/jsonl/index.js +18 -0
  72. package/dist/parsers/jsonl/model.d.ts +23 -0
  73. package/dist/parsers/jsonl/model.js +1 -0
  74. package/dist/parsers/jsonl/parse.d.ts +7 -0
  75. package/dist/parsers/jsonl/parse.js +34 -0
  76. package/dist/parsers/markdown/index.d.ts +37 -0
  77. package/dist/parsers/markdown/index.js +59 -0
  78. package/dist/parsers/mat/index.d.ts +31 -0
  79. package/dist/parsers/mat/index.js +426 -0
  80. package/dist/parsers/mermaid/index.d.ts +5 -0
  81. package/dist/parsers/mermaid/index.js +3 -0
  82. package/dist/parsers/mf4/index.d.ts +1 -0
  83. package/dist/parsers/mf4/index.js +1 -0
  84. package/dist/parsers/parquet/index.d.ts +21 -0
  85. package/dist/parsers/parquet/index.js +68 -0
  86. package/dist/parsers/pcap/index.d.ts +1 -0
  87. package/dist/parsers/pcap/index.js +1 -0
  88. package/dist/parsers/pcapng/index.d.ts +1 -0
  89. package/dist/parsers/pcapng/index.js +1 -0
  90. package/dist/parsers/plantuml/index.d.ts +5 -0
  91. package/dist/parsers/plantuml/index.js +4 -0
  92. package/dist/parsers/ppt-binary/index.d.ts +5 -0
  93. package/dist/parsers/ppt-binary/index.js +62 -0
  94. package/dist/parsers/ppt-binary/pptBinaryBuildContext.d.ts +12 -0
  95. package/dist/parsers/ppt-binary/pptBinaryBuildContext.js +40 -0
  96. package/dist/parsers/ppt-binary/pptBinaryContainer.d.ts +4 -0
  97. package/dist/parsers/ppt-binary/pptBinaryContainer.js +174 -0
  98. package/dist/parsers/ppt-binary/pptBinaryTypes.d.ts +125 -0
  99. package/dist/parsers/ppt-binary/pptBinaryTypes.js +1 -0
  100. package/dist/parsers/ppt-binary/pptSlideLayouts.d.ts +9 -0
  101. package/dist/parsers/ppt-binary/pptSlideLayouts.js +510 -0
  102. package/dist/parsers/ppt-binary/vscode-parser.d.ts +116 -0
  103. package/dist/parsers/ppt-binary/vscode-parser.js +2853 -0
  104. package/dist/parsers/ppt-binary/vscode.d.ts +4 -0
  105. package/dist/parsers/ppt-binary/vscode.js +12 -0
  106. package/dist/parsers/pptx/index.d.ts +15 -0
  107. package/dist/parsers/pptx/index.js +88 -0
  108. package/dist/parsers/pptx/vscode-parser.d.ts +167 -0
  109. package/dist/parsers/pptx/vscode-parser.js +1503 -0
  110. package/dist/parsers/pptx/vscode.d.ts +4 -0
  111. package/dist/parsers/pptx/vscode.js +18 -0
  112. package/dist/parsers/pptx/zip-reader.d.ts +3 -0
  113. package/dist/parsers/pptx/zip-reader.js +20 -0
  114. package/dist/parsers/proto/index.d.ts +90 -0
  115. package/dist/parsers/proto/index.js +197 -0
  116. package/dist/parsers/psd/index.d.ts +16 -0
  117. package/dist/parsers/psd/index.js +10 -0
  118. package/dist/parsers/shapefile/dbf.d.ts +23 -0
  119. package/dist/parsers/shapefile/dbf.js +112 -0
  120. package/dist/parsers/shapefile/index.d.ts +44 -0
  121. package/dist/parsers/shapefile/index.js +119 -0
  122. package/dist/parsers/shapefile/reproject.d.ts +10 -0
  123. package/dist/parsers/shapefile/reproject.js +41 -0
  124. package/dist/parsers/slide-model.d.ts +106 -0
  125. package/dist/parsers/slide-model.js +1 -0
  126. package/dist/parsers/toml/index.d.ts +15 -0
  127. package/dist/parsers/toml/index.js +18 -0
  128. package/dist/parsers/toml/model.d.ts +15 -0
  129. package/dist/parsers/toml/model.js +1 -0
  130. package/dist/parsers/toml/parse.d.ts +16 -0
  131. package/dist/parsers/toml/parse.js +266 -0
  132. package/dist/parsers/types.d.ts +103 -0
  133. package/dist/parsers/types.js +106 -0
  134. package/dist/parsers/video/index.d.ts +6 -0
  135. package/dist/parsers/video/index.js +2 -0
  136. package/dist/parsers/yaml/index.d.ts +16 -0
  137. package/dist/parsers/yaml/index.js +58 -0
  138. package/dist/parsers/yaml/model.d.ts +22 -0
  139. package/dist/parsers/yaml/model.js +1 -0
  140. package/dist/parsers/yaml/self-loading.d.ts +3 -0
  141. package/dist/parsers/yaml/self-loading.js +19 -0
  142. package/dist/parsers/zip-scan.d.ts +8 -0
  143. package/dist/parsers/zip-scan.js +80 -0
  144. package/dist/registry/container.d.ts +17 -0
  145. package/dist/registry/container.js +49 -0
  146. package/dist/registry/index.d.ts +133 -0
  147. package/dist/registry/index.js +348 -0
  148. package/dist/registry/probe.d.ts +3 -0
  149. package/dist/registry/probe.js +177 -0
  150. package/dist/registry/sniff.d.ts +17 -0
  151. package/dist/registry/sniff.js +57 -0
  152. package/dist/styles/archive.css +10 -0
  153. package/dist/styles/audio.css +66 -0
  154. package/dist/styles/automotive.css +1 -0
  155. package/dist/styles/csv.css +262 -0
  156. package/dist/styles/excel.css +212 -0
  157. package/dist/styles/fallback.css +48 -0
  158. package/dist/styles/hdf5.css +3 -0
  159. package/dist/styles/hwp.css +12 -0
  160. package/dist/styles/image.css +115 -0
  161. package/dist/styles/json.css +342 -0
  162. package/dist/styles/jsonl.css +1 -0
  163. package/dist/styles/markdown.css +10 -0
  164. package/dist/styles/mat.css +2 -0
  165. package/dist/styles/mermaid.css +1 -0
  166. package/dist/styles/parquet.css +2 -0
  167. package/dist/styles/pdf.css +551 -0
  168. package/dist/styles/plantuml.css +1 -0
  169. package/dist/styles/ppt.css +1 -0
  170. package/dist/styles/proto.css +2 -0
  171. package/dist/styles/psd.css +1 -0
  172. package/dist/styles/shapefile.css +25 -0
  173. package/dist/styles/toml.css +1 -0
  174. package/dist/styles/video.css +74 -0
  175. package/dist/styles/word.css +685 -0
  176. package/dist/styles/yaml.css +1 -0
  177. package/dist/viewers/a2l/index.d.ts +15 -0
  178. package/dist/viewers/a2l/index.js +5 -0
  179. package/dist/viewers/archive/archive-preview-decoder.d.ts +4 -0
  180. package/dist/viewers/archive/archive-preview-decoder.js +223 -0
  181. package/dist/viewers/archive/controller.d.ts +24 -0
  182. package/dist/viewers/archive/controller.js +18 -0
  183. package/dist/viewers/archive/index.d.ts +25 -0
  184. package/dist/viewers/archive/index.js +230 -0
  185. package/dist/viewers/archive/preview.d.ts +2 -0
  186. package/dist/viewers/archive/preview.js +2 -0
  187. package/dist/viewers/archive/styles.d.ts +1 -0
  188. package/dist/viewers/archive/styles.js +11 -0
  189. package/dist/viewers/arxml/index.d.ts +15 -0
  190. package/dist/viewers/arxml/index.js +5 -0
  191. package/dist/viewers/asc/index.d.ts +15 -0
  192. package/dist/viewers/asc/index.js +5 -0
  193. package/dist/viewers/audio/controller.d.ts +33 -0
  194. package/dist/viewers/audio/controller.js +49 -0
  195. package/dist/viewers/audio/engine.d.ts +44 -0
  196. package/dist/viewers/audio/engine.js +108 -0
  197. package/dist/viewers/audio/index.d.ts +92 -0
  198. package/dist/viewers/audio/index.js +448 -0
  199. package/dist/viewers/audio/self-loading.d.ts +7 -0
  200. package/dist/viewers/audio/self-loading.js +42 -0
  201. package/dist/viewers/audio/styles.d.ts +1 -0
  202. package/dist/viewers/audio/styles.js +73 -0
  203. package/dist/viewers/automotive/index.d.ts +8 -0
  204. package/dist/viewers/automotive/index.js +152 -0
  205. package/dist/viewers/automotive/styles.d.ts +1 -0
  206. package/dist/viewers/automotive/styles.js +1 -0
  207. package/dist/viewers/avro/index.d.ts +15 -0
  208. package/dist/viewers/avro/index.js +5 -0
  209. package/dist/viewers/bag/index.d.ts +15 -0
  210. package/dist/viewers/bag/index.js +5 -0
  211. package/dist/viewers/blf/index.d.ts +15 -0
  212. package/dist/viewers/blf/index.js +5 -0
  213. package/dist/viewers/csv/controller.d.ts +126 -0
  214. package/dist/viewers/csv/controller.js +598 -0
  215. package/dist/viewers/csv/index.d.ts +48 -0
  216. package/dist/viewers/csv/index.js +846 -0
  217. package/dist/viewers/csv/styles.d.ts +1 -0
  218. package/dist/viewers/csv/styles.js +267 -0
  219. package/dist/viewers/db3/index.d.ts +15 -0
  220. package/dist/viewers/db3/index.js +5 -0
  221. package/dist/viewers/dbc/index.d.ts +15 -0
  222. package/dist/viewers/dbc/index.js +5 -0
  223. package/dist/viewers/diagram.d.ts +14 -0
  224. package/dist/viewers/diagram.js +95 -0
  225. package/dist/viewers/excel/controller.d.ts +108 -0
  226. package/dist/viewers/excel/controller.js +548 -0
  227. package/dist/viewers/excel/grid.d.ts +28 -0
  228. package/dist/viewers/excel/grid.js +99 -0
  229. package/dist/viewers/excel/index.d.ts +37 -0
  230. package/dist/viewers/excel/index.js +620 -0
  231. package/dist/viewers/excel/self-loading.d.ts +6 -0
  232. package/dist/viewers/excel/self-loading.js +13 -0
  233. package/dist/viewers/excel/styles.d.ts +1 -0
  234. package/dist/viewers/excel/styles.js +216 -0
  235. package/dist/viewers/fallback/index.d.ts +17 -0
  236. package/dist/viewers/fallback/index.js +130 -0
  237. package/dist/viewers/fallback/styles.d.ts +1 -0
  238. package/dist/viewers/fallback/styles.js +49 -0
  239. package/dist/viewers/hdf5/index.d.ts +19 -0
  240. package/dist/viewers/hdf5/index.js +170 -0
  241. package/dist/viewers/hdf5/styles.d.ts +1 -0
  242. package/dist/viewers/hdf5/styles.js +4 -0
  243. package/dist/viewers/hwp/controller.d.ts +19 -0
  244. package/dist/viewers/hwp/controller.js +22 -0
  245. package/dist/viewers/hwp/index.d.ts +39 -0
  246. package/dist/viewers/hwp/index.js +271 -0
  247. package/dist/viewers/hwp/self-loading.d.ts +2 -0
  248. package/dist/viewers/hwp/self-loading.js +6 -0
  249. package/dist/viewers/hwp/styles.d.ts +1 -0
  250. package/dist/viewers/hwp/styles.js +13 -0
  251. package/dist/viewers/image/controller.d.ts +210 -0
  252. package/dist/viewers/image/controller.js +336 -0
  253. package/dist/viewers/image/decode.d.ts +54 -0
  254. package/dist/viewers/image/decode.js +150 -0
  255. package/dist/viewers/image/index.d.ts +38 -0
  256. package/dist/viewers/image/index.js +749 -0
  257. package/dist/viewers/image/limits.d.ts +18 -0
  258. package/dist/viewers/image/limits.js +20 -0
  259. package/dist/viewers/image/styles.d.ts +1 -0
  260. package/dist/viewers/image/styles.js +119 -0
  261. package/dist/viewers/json/controller.d.ts +89 -0
  262. package/dist/viewers/json/controller.js +411 -0
  263. package/dist/viewers/json/index.d.ts +25 -0
  264. package/dist/viewers/json/index.js +503 -0
  265. package/dist/viewers/json/styles.d.ts +1 -0
  266. package/dist/viewers/json/styles.js +346 -0
  267. package/dist/viewers/json/transforms.d.ts +27 -0
  268. package/dist/viewers/json/transforms.js +253 -0
  269. package/dist/viewers/jsonl/controller.d.ts +48 -0
  270. package/dist/viewers/jsonl/controller.js +136 -0
  271. package/dist/viewers/jsonl/index.d.ts +22 -0
  272. package/dist/viewers/jsonl/index.js +184 -0
  273. package/dist/viewers/jsonl/styles.d.ts +1 -0
  274. package/dist/viewers/jsonl/styles.js +1 -0
  275. package/dist/viewers/markdown/controller.d.ts +50 -0
  276. package/dist/viewers/markdown/controller.js +62 -0
  277. package/dist/viewers/markdown/index.d.ts +64 -0
  278. package/dist/viewers/markdown/index.js +425 -0
  279. package/dist/viewers/markdown/math.d.ts +21 -0
  280. package/dist/viewers/markdown/math.js +100 -0
  281. package/dist/viewers/markdown/self-loading.d.ts +5 -0
  282. package/dist/viewers/markdown/self-loading.js +48 -0
  283. package/dist/viewers/markdown/styles.d.ts +1 -0
  284. package/dist/viewers/markdown/styles.js +11 -0
  285. package/dist/viewers/mat/index.d.ts +19 -0
  286. package/dist/viewers/mat/index.js +113 -0
  287. package/dist/viewers/mat/styles.d.ts +1 -0
  288. package/dist/viewers/mat/styles.js +3 -0
  289. package/dist/viewers/media.d.ts +9 -0
  290. package/dist/viewers/media.js +77 -0
  291. package/dist/viewers/mermaid/index.d.ts +17 -0
  292. package/dist/viewers/mermaid/index.js +6 -0
  293. package/dist/viewers/mermaid/self-loading.d.ts +2 -0
  294. package/dist/viewers/mermaid/self-loading.js +2 -0
  295. package/dist/viewers/mf4/index.d.ts +15 -0
  296. package/dist/viewers/mf4/index.js +5 -0
  297. package/dist/viewers/parquet/controller.d.ts +37 -0
  298. package/dist/viewers/parquet/controller.js +26 -0
  299. package/dist/viewers/parquet/index.d.ts +23 -0
  300. package/dist/viewers/parquet/index.js +134 -0
  301. package/dist/viewers/parquet/styles.d.ts +1 -0
  302. package/dist/viewers/parquet/styles.js +3 -0
  303. package/dist/viewers/pcap/index.d.ts +15 -0
  304. package/dist/viewers/pcap/index.js +5 -0
  305. package/dist/viewers/pcapng/index.d.ts +15 -0
  306. package/dist/viewers/pcapng/index.js +5 -0
  307. package/dist/viewers/pdf/controller.d.ts +120 -0
  308. package/dist/viewers/pdf/controller.js +191 -0
  309. package/dist/viewers/pdf/editing.d.ts +26 -0
  310. package/dist/viewers/pdf/editing.js +265 -0
  311. package/dist/viewers/pdf/index.d.ts +88 -0
  312. package/dist/viewers/pdf/index.js +1400 -0
  313. package/dist/viewers/pdf/self-loading.d.ts +6 -0
  314. package/dist/viewers/pdf/self-loading.js +14 -0
  315. package/dist/viewers/pdf/styles.d.ts +1 -0
  316. package/dist/viewers/pdf/styles.js +555 -0
  317. package/dist/viewers/plantuml/index.d.ts +17 -0
  318. package/dist/viewers/plantuml/index.js +6 -0
  319. package/dist/viewers/plantuml/self-loading.d.ts +2 -0
  320. package/dist/viewers/plantuml/self-loading.js +2 -0
  321. package/dist/viewers/ppt/chart.d.ts +8 -0
  322. package/dist/viewers/ppt/chart.js +83 -0
  323. package/dist/viewers/ppt/controller.d.ts +34 -0
  324. package/dist/viewers/ppt/controller.js +27 -0
  325. package/dist/viewers/ppt/index.d.ts +33 -0
  326. package/dist/viewers/ppt/index.js +101 -0
  327. package/dist/viewers/ppt/render.d.ts +5 -0
  328. package/dist/viewers/ppt/render.js +144 -0
  329. package/dist/viewers/ppt/self-loading.d.ts +9 -0
  330. package/dist/viewers/ppt/self-loading.js +4 -0
  331. package/dist/viewers/ppt/styles.d.ts +1 -0
  332. package/dist/viewers/ppt/styles.js +1 -0
  333. package/dist/viewers/proto/index.d.ts +17 -0
  334. package/dist/viewers/proto/index.js +170 -0
  335. package/dist/viewers/proto/styles.d.ts +1 -0
  336. package/dist/viewers/proto/styles.js +2 -0
  337. package/dist/viewers/psd/index.d.ts +27 -0
  338. package/dist/viewers/psd/index.js +39 -0
  339. package/dist/viewers/psd/self-loading.d.ts +10 -0
  340. package/dist/viewers/psd/self-loading.js +20 -0
  341. package/dist/viewers/psd/styles.d.ts +1 -0
  342. package/dist/viewers/psd/styles.js +1 -0
  343. package/dist/viewers/reqif/index.d.ts +15 -0
  344. package/dist/viewers/reqif/index.js +5 -0
  345. package/dist/viewers/shapefile/index.d.ts +35 -0
  346. package/dist/viewers/shapefile/index.js +336 -0
  347. package/dist/viewers/shapefile/self-loading.d.ts +7 -0
  348. package/dist/viewers/shapefile/self-loading.js +32 -0
  349. package/dist/viewers/shapefile/styles.d.ts +1 -0
  350. package/dist/viewers/shapefile/styles.js +28 -0
  351. package/dist/viewers/stp/index.d.ts +15 -0
  352. package/dist/viewers/stp/index.js +5 -0
  353. package/dist/viewers/structured-styles.d.ts +1 -0
  354. package/dist/viewers/structured-styles.js +1 -0
  355. package/dist/viewers/structured.d.ts +36 -0
  356. package/dist/viewers/structured.js +138 -0
  357. package/dist/viewers/toml/controller.d.ts +38 -0
  358. package/dist/viewers/toml/controller.js +61 -0
  359. package/dist/viewers/toml/index.d.ts +18 -0
  360. package/dist/viewers/toml/index.js +34 -0
  361. package/dist/viewers/types.d.ts +36 -0
  362. package/dist/viewers/types.js +9 -0
  363. package/dist/viewers/video/controller.d.ts +29 -0
  364. package/dist/viewers/video/controller.js +54 -0
  365. package/dist/viewers/video/index.d.ts +18 -0
  366. package/dist/viewers/video/index.js +305 -0
  367. package/dist/viewers/video/styles.d.ts +1 -0
  368. package/dist/viewers/video/styles.js +79 -0
  369. package/dist/viewers/word/controller.d.ts +19 -0
  370. package/dist/viewers/word/controller.js +22 -0
  371. package/dist/viewers/word/docx-preprocess.d.ts +63 -0
  372. package/dist/viewers/word/docx-preprocess.js +136 -0
  373. package/dist/viewers/word/index.d.ts +32 -0
  374. package/dist/viewers/word/index.js +187 -0
  375. package/dist/viewers/word/normalize-docx.d.ts +2 -0
  376. package/dist/viewers/word/normalize-docx.js +50 -0
  377. package/dist/viewers/word/paginate.d.ts +1 -0
  378. package/dist/viewers/word/paginate.js +1035 -0
  379. package/dist/viewers/word/self-loading.d.ts +2 -0
  380. package/dist/viewers/word/self-loading.js +7 -0
  381. package/dist/viewers/word/styles.d.ts +1 -0
  382. package/dist/viewers/word/styles.js +686 -0
  383. package/dist/viewers/yaml/controller.d.ts +42 -0
  384. package/dist/viewers/yaml/controller.js +41 -0
  385. package/dist/viewers/yaml/index.d.ts +21 -0
  386. package/dist/viewers/yaml/index.js +20 -0
  387. package/package.json +375 -0
@@ -0,0 +1,348 @@
1
+ // Viewer registry — pure detection data, no dynamic loading (DESIGN.md §7,
2
+ // ADR 21). Adapters register the viewers they enable via their own explicit
3
+ // import map. For the pilot the descriptor list is hand-maintained from the
4
+ // viewer metadata exports; the build-time codegen replaces this when more
5
+ // viewers land (ADR 37).
6
+ import { asciiLower } from '../parsers/csv/index.js';
7
+ import { sniffTextViewer } from './sniff.js';
8
+ import { CONTAINER_SNIFF_BYTES, OFFICE_CONTAINER_BY_EXT, sniffContainer } from './container.js';
9
+ /** Raster image signatures (docs/viewers/image.md §1). SVG has no fixed magic
10
+ * and is handled by extension + text probe in the viewer, not here. */
11
+ export const IMAGE_MAGIC_SIGNATURES = [
12
+ [{ offset: 0, bytes: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] }], // PNG
13
+ [{ offset: 0, bytes: [0xff, 0xd8, 0xff] }], // JPEG
14
+ [{ offset: 0, bytes: [0x47, 0x49, 0x46, 0x38] }], // GIF87a/89a → 'GIF8'
15
+ [{ offset: 0, bytes: [0x42, 0x4d] }], // BMP → 'BM'
16
+ [
17
+ { offset: 0, bytes: [0x52, 0x49, 0x46, 0x46] }, // 'RIFF'
18
+ { offset: 8, bytes: [0x57, 0x45, 0x42, 0x50] } // 'WEBP'
19
+ ]
20
+ ];
21
+ export const AVRO_MAGIC_SIGNATURES = [[
22
+ { offset: 0, bytes: [0x4f, 0x62, 0x6a, 0x01] }
23
+ ]];
24
+ export const BAG_MAGIC_SIGNATURES = [[
25
+ { offset: 0, bytes: [0x23, 0x52, 0x4f, 0x53, 0x42, 0x41, 0x47, 0x20, 0x56, 0x32, 0x2e] }
26
+ ]];
27
+ export const STP_MAGIC_SIGNATURES = [[
28
+ { offset: 0, bytes: [0x49, 0x53, 0x4f, 0x2d, 0x31, 0x30, 0x33, 0x30, 0x33, 0x2d, 0x32, 0x31, 0x3b] }
29
+ ]];
30
+ export const DB3_MAGIC_SIGNATURES = [[
31
+ { offset: 0, bytes: [0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00] }
32
+ ]];
33
+ export const BLF_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x4c, 0x4f, 0x47, 0x47] }]];
34
+ export const MF4_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x4d, 0x44, 0x46, 0x20, 0x20, 0x20, 0x20, 0x20] }]];
35
+ export const PCAP_MAGIC_SIGNATURES = [
36
+ [{ offset: 0, bytes: [0xa1, 0xb2, 0xc3, 0xd4] }], [{ offset: 0, bytes: [0xd4, 0xc3, 0xb2, 0xa1] }],
37
+ [{ offset: 0, bytes: [0xa1, 0xb2, 0x3c, 0x4d] }], [{ offset: 0, bytes: [0x4d, 0x3c, 0xb2, 0xa1] }]
38
+ ];
39
+ export const PCAPNG_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x0a, 0x0d, 0x0d, 0x0a] }]];
40
+ export const PSD_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x38, 0x42, 0x50, 0x53] }]];
41
+ export const SHAPEFILE_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x00, 0x00, 0x27, 0x0a] }]];
42
+ /** Farthest byte any signature needs (WebP reaches offset 8 + 4 = 12). */
43
+ const signatureReach = (sigs) => Math.max(0, ...sigs.flat().map((run) => run.offset + run.bytes.length));
44
+ /**
45
+ * How many leading bytes an adapter should sniff for detection — the longest of
46
+ * the longest magicPrefix (PDF, 5B), the container signatures (OLE, 8B), and the
47
+ * image signatures (WebP, 12B). Stage-1 uses only these; container probing
48
+ * (stage 2) needs the whole file to read the central directory / CFB
49
+ * (docs/viewers/excel.md §5).
50
+ */
51
+ export const REQUIRED_SNIFF_BYTES = Math.max(5, CONTAINER_SNIFF_BYTES, signatureReach(IMAGE_MAGIC_SIGNATURES), signatureReach(AVRO_MAGIC_SIGNATURES), signatureReach(BAG_MAGIC_SIGNATURES), signatureReach(STP_MAGIC_SIGNATURES), signatureReach(DB3_MAGIC_SIGNATURES), signatureReach(MF4_MAGIC_SIGNATURES));
52
+ export const CSV_VIEWER_DESCRIPTOR = {
53
+ id: 'csv',
54
+ displayNameKey: 'csv.tableView',
55
+ extensions: ['csv', 'tsv'],
56
+ priority: 10,
57
+ requiredServices: [],
58
+ optionalServices: ['clipboard', 'save', 'writeback']
59
+ };
60
+ export const FALLBACK_VIEWER_DESCRIPTOR = {
61
+ id: 'fallback',
62
+ displayNameKey: 'fallback.title.text',
63
+ extensions: [],
64
+ priority: -1,
65
+ requiredServices: [],
66
+ optionalServices: []
67
+ };
68
+ export const PDF_VIEWER_DESCRIPTOR = {
69
+ id: 'pdf',
70
+ displayNameKey: 'pdf.title',
71
+ extensions: ['pdf'],
72
+ priority: 20,
73
+ magicPrefix: [0x25, 0x50, 0x44, 0x46, 0x2d], // '%PDF-'
74
+ requiredServices: [],
75
+ optionalServices: ['save', 'writeback', 'filePick']
76
+ };
77
+ export const PARQUET_MAGIC_SIGNATURES = [[{ offset: 0, bytes: [0x50, 0x41, 0x52, 0x31] }]];
78
+ export const PARQUET_VIEWER_DESCRIPTOR = { id: 'parquet', displayNameKey: 'parquet.title', extensions: ['parquet'], priority: 20, magicSignatures: PARQUET_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard', 'save'] };
79
+ export const AVRO_VIEWER_DESCRIPTOR = { id: 'avro', displayNameKey: 'avro.title', extensions: ['avro'], priority: 20, magicSignatures: AVRO_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
80
+ export const BAG_VIEWER_DESCRIPTOR = { id: 'bag', displayNameKey: 'bag.title', extensions: ['bag'], priority: 20, magicSignatures: BAG_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
81
+ export const STP_VIEWER_DESCRIPTOR = { id: 'stp', displayNameKey: 'stp.title', extensions: ['stp', 'step'], priority: 20, magicSignatures: STP_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
82
+ export const DB3_VIEWER_DESCRIPTOR = { id: 'db3', displayNameKey: 'db3.title', extensions: ['db3'], priority: 20, magicSignatures: DB3_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
83
+ export const REQIF_VIEWER_DESCRIPTOR = { id: 'reqif', displayNameKey: 'reqif.title', extensions: ['reqif'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
84
+ export const HDF5_MAGIC_PREFIX = [0x89, 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a];
85
+ // HDF5 permits a user block before the signature (offset 512, 1024, ...), so
86
+ // named files are admitted by extension and validated by the parser. A leading
87
+ // signature still enables extensionless content routing below.
88
+ export const HDF5_VIEWER_DESCRIPTOR = { id: 'hdf5', displayNameKey: 'hdf5.title', extensions: ['h5', 'hdf5', 'he5'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
89
+ export const MAT_VIEWER_DESCRIPTOR = { id: 'mat', displayNameKey: 'mat.title', extensions: ['mat'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
90
+ export const AUDIO_VIEWER_DESCRIPTOR = { id: 'audio', displayNameKey: 'audio.title', extensions: ['mp3', 'wav', 'pcm', 'aiff', 'aif', 'aifc', 'amr', 'awb', 'ogg', 'flac', 'ac3', 'aac', 'm4a'], priority: 20, requiredServices: [], optionalServices: [] };
91
+ export const VIDEO_VIEWER_DESCRIPTOR = { id: 'video', displayNameKey: 'video.title', extensions: ['mp4', 'mts', 'm2ts', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'], priority: 20, requiredServices: [], optionalServices: [] };
92
+ export const DBC_VIEWER_DESCRIPTOR = { id: 'dbc', displayNameKey: 'dbc.title', extensions: ['dbc'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
93
+ export const ARXML_VIEWER_DESCRIPTOR = { id: 'arxml', displayNameKey: 'arxml.title', extensions: ['arxml'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
94
+ export const A2L_VIEWER_DESCRIPTOR = { id: 'a2l', displayNameKey: 'a2l.title', extensions: ['a2l'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
95
+ export const ASC_VIEWER_DESCRIPTOR = { id: 'asc', displayNameKey: 'asc.title', extensions: ['asc'], priority: 20, requiredServices: [], optionalServices: ['clipboard'] };
96
+ export const BLF_VIEWER_DESCRIPTOR = { id: 'blf', displayNameKey: 'blf.title', extensions: ['blf'], priority: 20, magicSignatures: BLF_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
97
+ export const MF4_VIEWER_DESCRIPTOR = { id: 'mf4', displayNameKey: 'mf4.title', extensions: ['mf4'], priority: 20, magicSignatures: MF4_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
98
+ export const PCAP_VIEWER_DESCRIPTOR = { id: 'pcap', displayNameKey: 'pcap.title', extensions: ['pcap'], priority: 20, magicSignatures: PCAP_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
99
+ export const PCAPNG_VIEWER_DESCRIPTOR = { id: 'pcapng', displayNameKey: 'pcapng.title', extensions: ['pcapng'], priority: 20, magicSignatures: PCAPNG_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['clipboard'] };
100
+ export const MERMAID_VIEWER_DESCRIPTOR = { id: 'mermaid', displayNameKey: 'mermaid.title', extensions: ['mmd', 'mermaid'], priority: 20, requiredServices: [], optionalServices: [] };
101
+ export const PLANTUML_VIEWER_DESCRIPTOR = { id: 'plantuml', displayNameKey: 'plantuml.title', extensions: ['puml', 'plantuml', 'iuml'], priority: 20, requiredServices: [], optionalServices: [] };
102
+ export const SHAPEFILE_VIEWER_DESCRIPTOR = { id: 'shapefile', displayNameKey: 'shapefile.title', extensions: ['shp'], priority: 20, magicSignatures: SHAPEFILE_MAGIC_SIGNATURES, requiredServices: [], optionalServices: [] };
103
+ export const PSD_VIEWER_DESCRIPTOR = { id: 'psd', displayNameKey: 'psd.title', extensions: ['psd'], priority: 20, magicSignatures: PSD_MAGIC_SIGNATURES, requiredServices: [], optionalServices: [] };
104
+ export const JSON_VIEWER_DESCRIPTOR = {
105
+ id: 'json',
106
+ displayNameKey: 'json.treeView',
107
+ extensions: ['json'],
108
+ priority: 10,
109
+ // JSON has no signature; extensionless content sniffing is stage-2 (J17,
110
+ // docs/viewers/json.md) and not part of this synchronous descriptor.
111
+ requiredServices: [],
112
+ optionalServices: ['clipboard', 'save', 'writeback']
113
+ };
114
+ export const TOML_VIEWER_DESCRIPTOR = {
115
+ id: 'toml', displayNameKey: 'toml.treeView', extensions: ['toml'], priority: 10,
116
+ requiredServices: [], optionalServices: ['clipboard']
117
+ };
118
+ export const JSONL_VIEWER_DESCRIPTOR = {
119
+ id: 'jsonl', displayNameKey: 'jsonl.title', extensions: ['jsonl', 'ndjson', 'jsonlines'], priority: 10,
120
+ requiredServices: [], optionalServices: ['clipboard', 'save', 'writeback']
121
+ };
122
+ export const YAML_VIEWER_DESCRIPTOR = {
123
+ id: 'yaml', displayNameKey: 'yaml.treeView', extensions: ['yaml', 'yml'], priority: 10,
124
+ requiredServices: [], optionalServices: ['clipboard']
125
+ };
126
+ export const PROTO_VIEWER_DESCRIPTOR = {
127
+ id: 'proto', displayNameKey: 'proto.title', extensions: ['proto'], priority: 10,
128
+ requiredServices: [], optionalServices: ['clipboard']
129
+ };
130
+ /**
131
+ * Excel spans two containers (xlsx/xlsm are zip, xls is ole), so it has no
132
+ * single magicPrefix — the container is verified via OFFICE_CONTAINER_BY_EXT
133
+ * and, when ambiguous, probeContainer (docs/viewers/excel.md §5, X-감지).
134
+ */
135
+ export const EXCEL_VIEWER_DESCRIPTOR = {
136
+ id: 'excel',
137
+ displayNameKey: 'excel.tableView',
138
+ extensions: ['xlsx', 'xlsm', 'xlsb', 'ods', 'xls'],
139
+ priority: 15,
140
+ requiredServices: [],
141
+ optionalServices: ['clipboard', 'save']
142
+ };
143
+ export const PPT_VIEWER_DESCRIPTOR = { id: 'ppt', displayNameKey: 'ppt.title', extensions: ['pptx', 'ppt'], priority: 15, requiredServices: [], optionalServices: [] };
144
+ export const WORD_VIEWER_DESCRIPTOR = { id: 'word', displayNameKey: 'word.title', extensions: ['docx', 'doc'], priority: 15, requiredServices: [], optionalServices: ['print', 'navigation'] };
145
+ export const HWP_VIEWER_DESCRIPTOR = { id: 'hwp', displayNameKey: 'hwp.title', extensions: ['hwp', 'hwpx'], priority: 15, requiredServices: [], optionalServices: [] };
146
+ /**
147
+ * Image viewer detection metadata (docs/viewers/image.md §1). Background removal
148
+ * and sprite detection are optional host services (image.md I8), never
149
+ * requiredServices: gating them here would exclude the image viewer on platforms
150
+ * that don't provide them. SVG has no fixed magic — it is admitted by extension
151
+ * and the viewer's text probe (decode.ts).
152
+ */
153
+ export const IMAGE_VIEWER_DESCRIPTOR = {
154
+ id: 'image',
155
+ displayNameKey: 'image.title',
156
+ extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'],
157
+ priority: 15,
158
+ magicSignatures: IMAGE_MAGIC_SIGNATURES,
159
+ requiredServices: [],
160
+ optionalServices: ['save', 'writeback', 'backgroundRemoval', 'spriteDetection']
161
+ };
162
+ export const MARKDOWN_VIEWER_DESCRIPTOR = {
163
+ id: 'markdown', displayNameKey: 'markdown.title',
164
+ extensions: ['md', 'markdown', 'mdown', 'mkdn', 'mkd'], priority: 10,
165
+ requiredServices: [], optionalServices: ['clipboard', 'navigation', 'documentAssets', 'writeback']
166
+ };
167
+ export const ARCHIVE_MAGIC_SIGNATURES = [
168
+ [{ offset: 0, bytes: [0x50, 0x4b, 0x03, 0x04] }], [{ offset: 0, bytes: [0x50, 0x4b, 0x05, 0x06] }],
169
+ [{ offset: 257, bytes: [0x75, 0x73, 0x74, 0x61, 0x72] }], [{ offset: 0, bytes: [0x1f, 0x8b] }],
170
+ [{ offset: 0, bytes: [0x42, 0x5a, 0x68] }], [{ offset: 0, bytes: [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00] }],
171
+ [{ offset: 0, bytes: [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c] }], [{ offset: 0, bytes: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00] }], [{ offset: 0, bytes: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00] }]
172
+ ];
173
+ /** Archive is intentionally lower priority than Office container viewers. */
174
+ export const ARCHIVE_VIEWER_DESCRIPTOR = {
175
+ id: 'archive', displayNameKey: 'archive.title',
176
+ extensions: ['zip', 'jar', 'apk', 'tar', 'tgz', 'tar.gz', 'tbz', 'tbz2', 'tar.bz2', 'txz', 'tar.xz', 'gz', 'bz2', 'xz', '7z', 'rar', 'dmg'],
177
+ priority: 5, magicSignatures: ARCHIVE_MAGIC_SIGNATURES, requiredServices: [], optionalServices: ['save']
178
+ };
179
+ export const CORE_VIEWER_DESCRIPTORS = [
180
+ PDF_VIEWER_DESCRIPTOR,
181
+ AUDIO_VIEWER_DESCRIPTOR,
182
+ VIDEO_VIEWER_DESCRIPTOR,
183
+ DBC_VIEWER_DESCRIPTOR,
184
+ ARXML_VIEWER_DESCRIPTOR,
185
+ A2L_VIEWER_DESCRIPTOR,
186
+ ASC_VIEWER_DESCRIPTOR,
187
+ BLF_VIEWER_DESCRIPTOR,
188
+ MF4_VIEWER_DESCRIPTOR,
189
+ PCAP_VIEWER_DESCRIPTOR,
190
+ PCAPNG_VIEWER_DESCRIPTOR,
191
+ MERMAID_VIEWER_DESCRIPTOR,
192
+ PLANTUML_VIEWER_DESCRIPTOR,
193
+ SHAPEFILE_VIEWER_DESCRIPTOR,
194
+ PSD_VIEWER_DESCRIPTOR,
195
+ PARQUET_VIEWER_DESCRIPTOR,
196
+ AVRO_VIEWER_DESCRIPTOR,
197
+ BAG_VIEWER_DESCRIPTOR,
198
+ STP_VIEWER_DESCRIPTOR,
199
+ DB3_VIEWER_DESCRIPTOR,
200
+ REQIF_VIEWER_DESCRIPTOR,
201
+ HDF5_VIEWER_DESCRIPTOR,
202
+ MAT_VIEWER_DESCRIPTOR,
203
+ PPT_VIEWER_DESCRIPTOR,
204
+ WORD_VIEWER_DESCRIPTOR,
205
+ HWP_VIEWER_DESCRIPTOR,
206
+ EXCEL_VIEWER_DESCRIPTOR,
207
+ IMAGE_VIEWER_DESCRIPTOR,
208
+ MARKDOWN_VIEWER_DESCRIPTOR,
209
+ ARCHIVE_VIEWER_DESCRIPTOR,
210
+ CSV_VIEWER_DESCRIPTOR,
211
+ JSON_VIEWER_DESCRIPTOR,
212
+ TOML_VIEWER_DESCRIPTOR,
213
+ JSONL_VIEWER_DESCRIPTOR,
214
+ YAML_VIEWER_DESCRIPTOR,
215
+ PROTO_VIEWER_DESCRIPTOR,
216
+ FALLBACK_VIEWER_DESCRIPTOR
217
+ ];
218
+ export { looksLikeJsonDocument, looksLikeJsonl, looksLikeProto, sniffTextViewer } from './sniff.js';
219
+ export { CONTAINER_SNIFF_BYTES, OFFICE_CONTAINER_BY_EXT, OLE_MAGIC, ZIP_MAGIC, sniffContainer } from './container.js';
220
+ export { probeContainer } from './probe.js';
221
+ /**
222
+ * Detection (DESIGN.md §7): ASCII-lowercased extension matching with priority
223
+ * tie-breaking (stage 1). When no extension matches and a text sample is
224
+ * provided, content sniffing (J17, 부록 B-6) classifies signature-less text
225
+ * formats — the extension is always trusted first (§7 point 3).
226
+ *
227
+ * Container-format viewers (excel; later word/ppt/hwpx) share zip/ole
228
+ * signatures, so stage-1 verifies a trusted office extension against the actual
229
+ * bytes: a match confirms it, a contradicting container (or a container with no
230
+ * matching extension) returns 'ambiguous-container' for the caller to resolve
231
+ * with probeContainer (stage 2, docs/viewers/excel.md §5). Services the host
232
+ * cannot provide exclude a viewer whose requiredServices demand them.
233
+ */
234
+ export function detectViewer(fileName, availableServices = new Set(), descriptors = CORE_VIEWER_DESCRIPTORS, sniffBytes, sniffText) {
235
+ const lower = asciiLower(fileName);
236
+ const magicMatches = (d) => {
237
+ // No sniff bytes → trust the extension (offline-friendly, stage-1).
238
+ if (!sniffBytes)
239
+ return true;
240
+ if (d.magicPrefix) {
241
+ if (sniffBytes.byteLength < d.magicPrefix.length)
242
+ return false;
243
+ if (!d.magicPrefix.every((byte, i) => sniffBytes[i] === byte))
244
+ return false;
245
+ }
246
+ if (d.magicSignatures) {
247
+ const runMatches = (run) => sniffBytes.byteLength >= run.offset + run.bytes.length &&
248
+ run.bytes.every((byte, i) => sniffBytes[run.offset + i] === byte);
249
+ if (!d.magicSignatures.some((sig) => sig.every(runMatches)))
250
+ return false;
251
+ }
252
+ return true;
253
+ };
254
+ const servicesMet = (d) => d.requiredServices.every((s) => availableServices.has(s));
255
+ const container = sniffBytes ? sniffContainer(sniffBytes) : null;
256
+ const candidates = descriptors
257
+ .map((d) => ({ d, ext: d.extensions.find((ext) => lower.endsWith(`.${ext}`)) }))
258
+ .filter((c) => c.ext !== undefined)
259
+ .filter((c) => servicesMet(c.d))
260
+ // DMG has a tail signature, checked by its decoder; it cannot be
261
+ // represented by leading-byte magic matching.
262
+ .filter((c) => c.d.id === 'archive' ? archiveMagicMatches(c.ext, sniffBytes) : magicMatches(c.d))
263
+ .sort((a, b) => b.d.priority - a.d.priority);
264
+ const winner = candidates[0];
265
+ if (winner) {
266
+ const expected = OFFICE_CONTAINER_BY_EXT[winner.ext];
267
+ // A trusted office extension whose bytes are a *different* container is
268
+ // a contradiction (§7-3) — hand off to stage-2 probing. Non-container
269
+ // or unreadable bytes fall back to trusting the extension (offline-
270
+ // friendly; the parser reports invalid-format if it truly isn't one).
271
+ if (expected && container && container !== expected) {
272
+ return { viewerId: 'fallback', matchedBy: 'ambiguous-container', container };
273
+ }
274
+ return { viewerId: winner.d.id, matchedBy: 'extension' };
275
+ }
276
+ // No extension match. Container bytes are ambiguous → probe decides.
277
+ if (container) {
278
+ return { viewerId: 'fallback', matchedBy: 'ambiguous-container', container };
279
+ }
280
+ if (sniffBytes && HDF5_MAGIC_PREFIX.every((byte, index) => sniffBytes[index] === byte)) {
281
+ const hdf5 = descriptors.find(d => d.id === 'hdf5');
282
+ if (hdf5 && servicesMet(hdf5))
283
+ return { viewerId: 'hdf5', matchedBy: 'content' };
284
+ }
285
+ if (sniffBytes && looksLikeClassicMat(sniffBytes)) {
286
+ const mat = descriptors.find(d => d.id === 'mat');
287
+ if (mat && servicesMet(mat))
288
+ return { viewerId: 'mat', matchedBy: 'content' };
289
+ }
290
+ if (sniffBytes) {
291
+ const unambiguous = descriptors.find(d => ['avro', 'bag', 'stp', 'db3', 'blf', 'mf4', 'pcap', 'pcapng', 'shapefile', 'psd'].includes(d.id) && servicesMet(d) && magicMatches(d));
292
+ if (unambiguous)
293
+ return { viewerId: unambiguous.id, matchedBy: 'content' };
294
+ }
295
+ // Non-ZIP archive formats have unambiguous leading magic. ZIP stays on the
296
+ // container-probe path above so Office/HWPX gets first refusal.
297
+ if (sniffBytes && !ARCHIVE_VIEWER_DESCRIPTOR.extensions.some(ext => lower.endsWith(`.${ext}`)) && ARCHIVE_MAGIC_SIGNATURES.slice(2).some(sig => sig.every(run => run.bytes.every((b, i) => sniffBytes[run.offset + i] === b)))) {
298
+ const archive = descriptors.find(d => d.id === 'archive');
299
+ if (archive && servicesMet(archive))
300
+ return { viewerId: 'archive', matchedBy: 'content' };
301
+ }
302
+ // Stage 2 (text content sniffing) — only when the extension gave no match.
303
+ if (sniffText !== undefined) {
304
+ const sniffedId = sniffTextViewer(sniffText);
305
+ if (sniffedId) {
306
+ const d = descriptors.find((x) => x.id === sniffedId);
307
+ if (d && servicesMet(d))
308
+ return { viewerId: d.id, matchedBy: 'content' };
309
+ }
310
+ }
311
+ return { viewerId: 'fallback', matchedBy: 'fallback' };
312
+ }
313
+ function looksLikeClassicMat(bytes) {
314
+ if (bytes.length < 19)
315
+ return false;
316
+ let header = '';
317
+ for (let i = 0; i < Math.min(bytes.length, 116); i++)
318
+ header += String.fromCharCode(bytes[i]);
319
+ return /^MATLAB\s+(?:5\.0|7\.)\s+MAT-file/i.test(header);
320
+ }
321
+ function archiveMagicMatches(ext, bytes) {
322
+ if (!bytes)
323
+ return true;
324
+ const starts = (...magic) => magic.every((x, i) => bytes[i] === x);
325
+ const zip = starts(0x50, 0x4b, 0x03, 0x04) || starts(0x50, 0x4b, 0x05, 0x06);
326
+ const tar = bytes.length >= 262 && [0x75, 0x73, 0x74, 0x61, 0x72].every((x, i) => bytes[257 + i] === x);
327
+ const gzip = starts(0x1f, 0x8b), bzip = starts(0x42, 0x5a, 0x68), xz = starts(0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00), seven = starts(0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c), rar = starts(0x52, 0x61, 0x72, 0x21, 0x1a, 0x07);
328
+ // DMG has no leading magic. A standard sniff contains only the head of
329
+ // the file, so the registry must trust its extension; parseArchive owns
330
+ // validation of the `koly` signature in the final 512-byte trailer.
331
+ if (ext === 'dmg')
332
+ return true;
333
+ if (['zip', 'jar', 'apk'].includes(ext))
334
+ return zip;
335
+ if (ext === 'tar')
336
+ return tar;
337
+ if (['tgz', 'tar.gz', 'gz'].includes(ext))
338
+ return gzip;
339
+ if (['tbz', 'tbz2', 'tar.bz2', 'bz2'].includes(ext))
340
+ return bzip;
341
+ if (['txz', 'tar.xz', 'xz'].includes(ext))
342
+ return xz;
343
+ if (ext === '7z')
344
+ return seven;
345
+ if (ext === 'rar')
346
+ return rar;
347
+ return false;
348
+ }
@@ -0,0 +1,3 @@
1
+ import type { ParseOptions } from '../parsers/types.js';
2
+ import type { ContainerKind } from './container.js';
3
+ export declare function probeContainer(input: Uint8Array, container: ContainerKind, options?: ParseOptions): Promise<string | null>;
@@ -0,0 +1,177 @@
1
+ // Stage-2 container probe (DESIGN.md §7-3·ADR 16, docs/viewers/excel.md §5).
2
+ // Given bytes already known to be a zip/ole container (sniffContainer), look
3
+ // *inside* to decide which viewer holds it. Dependency-free and defensive —
4
+ // any structural anomaly returns null (→ fallback), never throws, so this can
5
+ // run before any heavy parser dependency is loaded.
6
+ /** Default cap on entries/directory records a probe will scan. */
7
+ const DEFAULT_PROBE_ENTRY_CAP = 4096;
8
+ export async function probeContainer(input, container, options = {}) {
9
+ // Async signature for contract symmetry (§5) and future worker/streaming;
10
+ // the current implementations are synchronous scans over an in-memory view.
11
+ if (options.signal?.aborted)
12
+ return null;
13
+ return container === 'zip' ? probeZip(input, options) : probeOle(input, options);
14
+ }
15
+ // ─── ZIP (OOXML / ODF) ────────────────────────────────────────────────────
16
+ // Parse the End Of Central Directory, then walk the central directory file
17
+ // headers collecting entry names. OOXML members live under `xl/`, `word/`,
18
+ // `ppt/`; ODF carries a `mimetype` member; a bare zip/jar matches none.
19
+ const EOCD_SIG = 0x06054b50; // PK\x05\x06 (little-endian uint32)
20
+ const CDFH_SIG = 0x02014b50; // PK\x01\x02
21
+ function probeZip(input, options) {
22
+ const view = new DataView(input.buffer, input.byteOffset, input.byteLength);
23
+ const eocd = findEocd(view);
24
+ if (eocd < 0)
25
+ return null;
26
+ const entryCount = view.getUint16(eocd + 10, true);
27
+ const cdOffset = view.getUint32(eocd + 16, true);
28
+ const cap = Math.min(entryCount, options.limits?.maxEntries ?? DEFAULT_PROBE_ENTRY_CAP);
29
+ let pos = cdOffset;
30
+ for (let i = 0; i < cap; i++) {
31
+ if (options.signal?.aborted)
32
+ return null;
33
+ if (pos + 46 > view.byteLength)
34
+ break;
35
+ if (view.getUint32(pos, true) !== CDFH_SIG)
36
+ break;
37
+ const nameLen = view.getUint16(pos + 28, true);
38
+ const extraLen = view.getUint16(pos + 30, true);
39
+ const commentLen = view.getUint16(pos + 32, true);
40
+ const nameStart = pos + 46;
41
+ if (nameStart + nameLen > view.byteLength)
42
+ break;
43
+ const name = asciiName(input, nameStart, nameLen);
44
+ // OOXML (xlsx/xlsm/xlsb, docx, pptx) route by member-path prefix.
45
+ if (name.startsWith('xl/'))
46
+ return 'excel';
47
+ if (name.startsWith('word/'))
48
+ return 'word';
49
+ if (name.startsWith('ppt/'))
50
+ return 'ppt';
51
+ if (name.startsWith('Contents/') || name === 'content.hpf')
52
+ return 'hwp';
53
+ // ODF (.ods/.odt/.odp) — the stored `mimetype` member carries the type.
54
+ if (name === 'mimetype') {
55
+ const localOffset = view.getUint32(pos + 42, true);
56
+ const storedSize = view.getUint32(pos + 20, true);
57
+ const mimetype = readStoredEntry(input, view, localOffset, storedSize);
58
+ if (mimetype.trim() === 'application/hwp+zip')
59
+ return 'hwp';
60
+ if (mimetype.includes('spreadsheet'))
61
+ return 'excel';
62
+ if (mimetype.includes('text') || mimetype.includes('presentation'))
63
+ return null;
64
+ }
65
+ pos = nameStart + nameLen + extraLen + commentLen;
66
+ }
67
+ // OOXML content-types with no recognized part prefix, or a plain zip/jar.
68
+ return null;
69
+ }
70
+ /** Scan backwards for the EOCD signature (record is 22 bytes + comment). */
71
+ function findEocd(view) {
72
+ const min = Math.max(0, view.byteLength - (22 + 0xffff));
73
+ for (let pos = view.byteLength - 22; pos >= min; pos--) {
74
+ if (view.getUint32(pos, true) === EOCD_SIG)
75
+ return pos;
76
+ }
77
+ return -1;
78
+ }
79
+ function asciiName(bytes, start, len) {
80
+ let out = '';
81
+ for (let i = 0; i < len; i++) {
82
+ out += String.fromCharCode(bytes[start + i]);
83
+ }
84
+ return out;
85
+ }
86
+ const LFH_SIG = 0x04034b50; // PK\x03\x04 (local file header)
87
+ /** Read a STORED (uncompressed) entry's bytes as ASCII — used for the ODF
88
+ * `mimetype` member, which spec-mandates be the first, stored entry. */
89
+ function readStoredEntry(bytes, view, localOffset, size) {
90
+ if (localOffset < 0 || localOffset + 30 > view.byteLength)
91
+ return '';
92
+ if (view.getUint32(localOffset, true) !== LFH_SIG)
93
+ return '';
94
+ const nameLen = view.getUint16(localOffset + 26, true);
95
+ const extraLen = view.getUint16(localOffset + 28, true);
96
+ const dataStart = localOffset + 30 + nameLen + extraLen;
97
+ const end = Math.min(dataStart + size, view.byteLength);
98
+ if (dataStart >= end)
99
+ return '';
100
+ return asciiName(bytes, dataStart, end - dataStart);
101
+ }
102
+ // ─── OLE / CFB (legacy Office) ──────────────────────────────────────────────
103
+ // Parse the Compound File header, follow the directory sector chain via the
104
+ // FAT, and read directory entry names. Excel BIFF workbooks carry a `Workbook`
105
+ // (BIFF8) or `Book` (BIFF5) stream.
106
+ const CFB_ENDOFCHAIN = 0xfffffffe;
107
+ const CFB_FREESECT = 0xffffffff;
108
+ function probeOle(input, options) {
109
+ if (input.byteLength < 512)
110
+ return null;
111
+ const view = new DataView(input.buffer, input.byteOffset, input.byteLength);
112
+ const sectorShift = view.getUint16(30, true);
113
+ const sectorSize = 1 << sectorShift;
114
+ if (sectorSize !== 512 && sectorSize !== 4096)
115
+ return null;
116
+ const numFatSectors = view.getUint32(44, true);
117
+ const dirStart = view.getUint32(48, true);
118
+ const sectorOffset = (sid) => (sid + 1) * sectorSize;
119
+ const readU32 = (off) => off + 4 <= view.byteLength ? view.getUint32(off, true) : CFB_ENDOFCHAIN;
120
+ // Build the FAT from the header DIFAT (first 109 entries). Enough to follow
121
+ // the directory chain in typical office files; DIFAT-extension sectors are
122
+ // out of scope for a probe (returns null if the chain can't be followed).
123
+ const fat = [];
124
+ const fatSectorCount = Math.min(numFatSectors, 109);
125
+ for (let i = 0; i < fatSectorCount; i++) {
126
+ const fatSid = view.getUint32(76 + i * 4, true);
127
+ if (fatSid === CFB_FREESECT || fatSid === CFB_ENDOFCHAIN)
128
+ continue;
129
+ const base = sectorOffset(fatSid);
130
+ if (base + sectorSize > view.byteLength)
131
+ break;
132
+ for (let j = 0; j < sectorSize; j += 4)
133
+ fat.push(readU32(base + j));
134
+ }
135
+ if (fat.length === 0)
136
+ return null;
137
+ const decoder = new TextDecoder('utf-16le');
138
+ const cap = options.limits?.maxEntries ?? DEFAULT_PROBE_ENTRY_CAP;
139
+ let sid = dirStart;
140
+ let scanned = 0;
141
+ const seen = new Set();
142
+ let hasHwpFileHeader = false;
143
+ let hasHwpBodyText = false;
144
+ while (sid !== CFB_ENDOFCHAIN && sid !== CFB_FREESECT && scanned < cap) {
145
+ if (options.signal?.aborted)
146
+ return null;
147
+ if (sid < 0 || sid >= fat.length || seen.has(sid))
148
+ break; // out of range / cycle
149
+ seen.add(sid);
150
+ const base = sectorOffset(sid);
151
+ if (base + sectorSize > view.byteLength)
152
+ break;
153
+ for (let off = base; off + 128 <= base + sectorSize; off += 128) {
154
+ if (scanned++ >= cap)
155
+ break;
156
+ const nameLen = view.getUint16(off + 64, true);
157
+ const objType = view.getUint8(off + 66);
158
+ if (objType !== 1 /* storage */ && objType !== 2 /* stream */)
159
+ continue;
160
+ if (nameLen < 4 || nameLen > 64)
161
+ continue;
162
+ const name = decoder.decode(input.subarray(off, off + nameLen - 2));
163
+ if (objType === 2 && (name === 'Workbook' || name === 'Book'))
164
+ return 'excel';
165
+ if (objType === 2 && name === 'WordDocument')
166
+ return 'word';
167
+ if (objType === 2 && name === 'PowerPoint Document')
168
+ return 'ppt';
169
+ if (objType === 2 && name === 'FileHeader')
170
+ hasHwpFileHeader = true;
171
+ if (objType === 1 && name === 'BodyText')
172
+ hasHwpBodyText = true;
173
+ }
174
+ sid = fat[sid] ?? CFB_ENDOFCHAIN;
175
+ }
176
+ return hasHwpFileHeader && hasHwpBodyText ? 'hwp' : null;
177
+ }
@@ -0,0 +1,17 @@
1
+ /** True if `text` parses cleanly as a single JSON object or array. */
2
+ export declare function looksLikeJsonDocument(text: string): boolean;
3
+ /**
4
+ * True if `text` looks like line-delimited JSON: at least two non-blank lines
5
+ * where each of the first ten parses to a JSON object or array. Blank lines are
6
+ * ignored so a trailing newline does not disqualify the file.
7
+ */
8
+ export declare function looksLikeJsonl(text: string): boolean;
9
+ /** Conservative Protocol Buffer schema detection for extensionless text. */
10
+ export declare function looksLikeProto(text: string): boolean;
11
+ /**
12
+ * Classify a text sample to a viewer id by content (JSONL is checked before
13
+ * JSON — 부록 B-6). Returns null when nothing matches. JSONL wins over JSON for
14
+ * multi-line object streams so a `{…}\n{…}` file is never mis-claimed as JSON;
15
+ * if no jsonl viewer is registered the caller falls through to fallback.
16
+ */
17
+ export declare function sniffTextViewer(text: string): 'jsonl' | 'json' | 'proto' | null;
@@ -0,0 +1,57 @@
1
+ // Content sniffing for signature-less text formats (J17, docs/viewers/json.md
2
+ // 부록 B-6). JSON has no magic bytes, so extensionless JSON is detected by
3
+ // parsing a content sample. Deterministic: uses the core JSON parser (never
4
+ // JSON.parse, ADR 41), so the boolean is identical across engines. The
5
+ // legacy platforms (vscode/obsidian/chrome) sniff the same way — dropping this
6
+ // would regress them for extensionless files.
7
+ import { parseJson } from '../parsers/json/index.js';
8
+ /** True if `text` parses cleanly as a single JSON object or array. */
9
+ export function looksLikeJsonDocument(text) {
10
+ const trimmed = text.trim();
11
+ if (!trimmed.startsWith('{') && !trimmed.startsWith('['))
12
+ return false;
13
+ const { result } = parseJson(trimmed);
14
+ if (result.status !== 'ok')
15
+ return false;
16
+ const kind = result.document.root.kind;
17
+ return kind === 'object' || kind === 'array';
18
+ }
19
+ /**
20
+ * True if `text` looks like line-delimited JSON: at least two non-blank lines
21
+ * where each of the first ten parses to a JSON object or array. Blank lines are
22
+ * ignored so a trailing newline does not disqualify the file.
23
+ */
24
+ export function looksLikeJsonl(text) {
25
+ const lines = text.split(/\r\n|\r|\n/).filter((line) => line.trim().length > 0);
26
+ if (lines.length < 2)
27
+ return false;
28
+ return lines.slice(0, 10).every((line) => {
29
+ const { result } = parseJson(line);
30
+ if (result.status !== 'ok')
31
+ return false;
32
+ const kind = result.document.root.kind;
33
+ return kind === 'object' || kind === 'array';
34
+ });
35
+ }
36
+ /** Conservative Protocol Buffer schema detection for extensionless text. */
37
+ export function looksLikeProto(text) {
38
+ const sample = text.slice(0, 64 * 1024).replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
39
+ if (/^\s*syntax\s*=\s*["']proto[23]["']\s*;/m.test(sample))
40
+ return true;
41
+ return /^\s*(?:package\s+[\w.]+\s*;\s*)?(?:import\s+(?:(?:public|weak)\s+)?["'][^"']+["']\s*;\s*)*(?:message|enum|service)\s+[A-Za-z_]\w*\s*\{/m.test(sample);
42
+ }
43
+ /**
44
+ * Classify a text sample to a viewer id by content (JSONL is checked before
45
+ * JSON — 부록 B-6). Returns null when nothing matches. JSONL wins over JSON for
46
+ * multi-line object streams so a `{…}\n{…}` file is never mis-claimed as JSON;
47
+ * if no jsonl viewer is registered the caller falls through to fallback.
48
+ */
49
+ export function sniffTextViewer(text) {
50
+ if (looksLikeJsonl(text))
51
+ return 'jsonl';
52
+ if (looksLikeJsonDocument(text))
53
+ return 'json';
54
+ if (looksLikeProto(text))
55
+ return 'proto';
56
+ return null;
57
+ }
@@ -0,0 +1,10 @@
1
+
2
+ .omni-viewer--archive{all:initial}.omni-viewer--archive :where(header,section,aside,div,h1,h2,p,span,label,input,table,thead,tbody,tr,th,td,pre){all:revert}
3
+ :host,.omni-viewer--archive{display:block;min-height:100%;box-sizing:border-box;color:var(--omni-fg,#d4d4d4);background:radial-gradient(circle at top left,color-mix(in srgb,var(--omni-accent,#d97706) 14%,transparent),transparent 28%),var(--omni-bg,#1e1e1e);font:13px var(--omni-font,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif)}
4
+ .omni-viewer--archive *{box-sizing:border-box}.omni-viewer--archive{padding:28px 20px 40px}.omni-archive__hero,.omni-archive__controls,.omni-archive__stats,.omni-archive__table-wrap,.omni-archive__preview-panel{background:var(--omni-bg-secondary,#252526);border:1px solid var(--omni-border,#3c3c3c);border-radius:18px;box-shadow:0 20px 40px rgba(0,0,0,.12)}
5
+ .omni-archive__hero{display:flex;justify-content:space-between;gap:16px;padding:24px;align-items:flex-start}.omni-archive__eyebrow{font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:var(--omni-accent,#d97706);font-weight:700}.omni-archive__hero h1{margin:8px 0 6px;font-size:clamp(26px,4vw,40px);line-height:1.1}.omni-archive__subtitle,.omni-archive__preview-meta{color:var(--omni-muted-fg,#9d9d9d);line-height:1.5}.omni-archive__pills{display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-end}.omni-archive__pill{padding:10px 14px;border-radius:999px;background:color-mix(in srgb,var(--omni-accent,#d97706) 16%,transparent);border:1px solid color-mix(in srgb,var(--omni-accent,#d97706) 35%,transparent);font-weight:600;white-space:nowrap}
6
+ .omni-archive__controls,.omni-archive__stats,.omni-archive__workspace{margin-top:16px}.omni-archive__controls{padding:16px}.omni-archive__search-label{display:block;font-weight:600}.omni-archive__search{display:block;width:100%;margin-top:8px;padding:12px 14px;border-radius:12px;border:1px solid var(--omni-border,#3c3c3c);background:var(--omni-input-bg,#3c3c3c);color:var(--omni-fg,#d4d4d4);font:inherit}.omni-archive__stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;padding:16px}.omni-archive__stat{padding:14px;border-radius:14px;background:color-mix(in srgb,var(--omni-bg-secondary,#252526) 76%,#000);border:1px solid var(--omni-border,#3c3c3c)}.omni-archive__stat-label{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--omni-muted-fg,#9d9d9d);margin-bottom:6px}.omni-archive__stat-value{font-size:24px;font-weight:700}
7
+ .omni-archive__workspace{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(320px,.95fr);gap:16px;align-items:start}.omni-archive__table-wrap{overflow:auto;min-width:0;max-height:70vh}.omni-archive__table{width:100%;table-layout:fixed;border-collapse:collapse}.omni-archive__table th,.omni-archive__table td{padding:12px 14px;border-bottom:1px solid var(--omni-border,#3c3c3c);text-align:left;vertical-align:top;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.omni-archive__table th:first-child{width:42%}.omni-archive__table th{position:sticky;top:0;font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--omni-muted-fg,#9d9d9d);background:var(--omni-bg-secondary,#252526);z-index:1}.omni-archive__path{font-family:var(--omni-mono-font,"SFMono-Regular",Consolas,monospace)}.omni-archive__entry{height:43px;cursor:pointer;transition:background-color 120ms ease}.omni-archive__entry:hover{background:color-mix(in srgb,var(--omni-accent,#d97706) 8%,transparent)}.omni-archive__entry:focus-visible{outline:2px solid var(--omni-accent,#d97706);outline-offset:-2px}.omni-archive__entry.is-selected{background:color-mix(in srgb,var(--omni-accent,#d97706) 16%,transparent)}.omni-archive__empty{padding:26px 18px;text-align:center;color:var(--omni-muted-fg,#9d9d9d)}
8
+ .omni-archive__preview-panel{padding:18px;min-height:420px;display:flex;flex-direction:column;gap:14px}.omni-archive__preview-header{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.omni-archive__preview-kicker{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--omni-muted-fg,#9d9d9d);margin-bottom:6px}.omni-archive__preview-header h2{margin:0;font-size:18px;line-height:1.35;word-break:break-word}.omni-archive__preview-badge{border-radius:999px;padding:8px 12px;font-size:12px;font-weight:700;background:var(--omni-badge-bg,#3a3d41);white-space:nowrap}.omni-archive__preview-meta{margin:0}.omni-archive__preview{margin:0;flex:1;overflow:auto;white-space:pre-wrap;word-break:break-word;border-radius:14px;border:1px solid var(--omni-border,#3c3c3c);background:var(--omni-code-bg,#181818);padding:14px;color:var(--omni-fg,#d4d4d4);font:12px/1.55 var(--omni-mono-font,"SFMono-Regular",Consolas,monospace)}
9
+ .omni-archive__save{align-self:flex-start;padding:8px 12px;border:1px solid var(--omni-border,#3c3c3c);border-radius:6px;background:var(--omni-button-bg,#3a3d41);color:var(--omni-fg,#d4d4d4);font:inherit;cursor:pointer}.omni-archive__save:hover:not(:disabled){background:var(--omni-button-hover-bg,#45494e)}.omni-archive__save:disabled{opacity:.55;cursor:not-allowed}.omni-archive__spacer td{padding:0!important;border:0!important}
10
+ @media(max-width:720px){.omni-viewer--archive{padding:16px 10px 24px}.omni-archive__hero{flex-direction:column}.omni-archive__pills{justify-content:flex-start}.omni-archive__table th:nth-child(n+3),.omni-archive__table td:nth-child(n+3){display:none}.omni-archive__workspace{grid-template-columns:1fr}.omni-archive__preview-panel{min-height:280px}}