nuxt-ai-ready 2.5.0 → 2.5.2

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 (206) hide show
  1. package/dist/chunks/agent-skills.mjs +1 -1
  2. package/dist/chunks/prerender.mjs +1 -1
  3. package/dist/cli.mjs +2 -0
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +1 -1
  6. package/dist/runtime/server/db/drizzle/queries.js +0 -1
  7. package/dist/runtime/server/db/queries.d.ts +2 -0
  8. package/dist/runtime/server/db/queries.js +11 -5
  9. package/dist/runtime/server/db/seed.d.ts +2 -2
  10. package/dist/runtime/server/routes/__ai-ready/reindex.post.js +2 -0
  11. package/dist/runtime/server/utils/batchIndex.js +4 -2
  12. package/dist/runtime/server/utils/checkStale.d.ts +1 -1
  13. package/dist/runtime/server/utils/checkStale.js +1 -1
  14. package/dist/runtime/server/utils/indexPage.d.ts +8 -1
  15. package/dist/runtime/server/utils/indexPage.js +13 -5
  16. package/dist/shared/{nuxt-ai-ready.DsokNmXc.mjs → nuxt-ai-ready.CLSWou20.mjs} +2 -0
  17. package/node_modules/@mdream/js/LICENSE.md +9 -0
  18. package/node_modules/@mdream/js/README.md +792 -0
  19. package/node_modules/@mdream/js/bin/mdream.mjs +2 -0
  20. package/node_modules/@mdream/js/dist/_chunks/const.mjs +134 -0
  21. package/node_modules/@mdream/js/dist/_chunks/index.d.mts +9 -0
  22. package/node_modules/@mdream/js/dist/_chunks/markdown-processor.mjs +1968 -0
  23. package/node_modules/@mdream/js/dist/_chunks/minimal.d.mts +6 -0
  24. package/node_modules/@mdream/js/dist/_chunks/parse.mjs +2756 -0
  25. package/node_modules/@mdream/js/dist/_chunks/plugins.mjs +725 -0
  26. package/node_modules/@mdream/js/dist/_chunks/resolve-plugins.mjs +44 -0
  27. package/node_modules/@mdream/js/dist/_chunks/stream.mjs +37 -0
  28. package/node_modules/@mdream/js/dist/_chunks/types.d.mts +473 -0
  29. package/node_modules/@mdream/js/dist/cli.d.mts +1 -0
  30. package/node_modules/@mdream/js/dist/cli.mjs +32 -0
  31. package/node_modules/@mdream/js/dist/core.d.mts +15 -0
  32. package/node_modules/@mdream/js/dist/core.mjs +28 -0
  33. package/node_modules/@mdream/js/dist/index.d.mts +4 -0
  34. package/node_modules/@mdream/js/dist/index.mjs +58 -0
  35. package/node_modules/@mdream/js/dist/llms-txt.d.mts +86 -0
  36. package/node_modules/@mdream/js/dist/llms-txt.mjs +308 -0
  37. package/node_modules/@mdream/js/dist/negotiate.d.mts +35 -0
  38. package/node_modules/@mdream/js/dist/negotiate.mjs +121 -0
  39. package/node_modules/@mdream/js/dist/parse.d.mts +90 -0
  40. package/node_modules/@mdream/js/dist/parse.mjs +2 -0
  41. package/node_modules/@mdream/js/dist/plugins.d.mts +85 -0
  42. package/node_modules/@mdream/js/dist/plugins.mjs +2 -0
  43. package/node_modules/@mdream/js/dist/preset/minimal.d.mts +2 -0
  44. package/node_modules/@mdream/js/dist/preset/minimal.mjs +33 -0
  45. package/node_modules/@mdream/js/dist/splitter.d.mts +18 -0
  46. package/node_modules/@mdream/js/dist/splitter.mjs +194 -0
  47. package/node_modules/@mdream/js/package.json +103 -0
  48. package/node_modules/cac/LICENSE +21 -0
  49. package/node_modules/cac/README.md +492 -0
  50. package/node_modules/cac/dist/index.d.ts +196 -0
  51. package/node_modules/cac/dist/index.js +638 -0
  52. package/node_modules/cac/package.json +72 -0
  53. package/node_modules/mdream/LICENSE.md +9 -0
  54. package/node_modules/mdream/README.md +1091 -0
  55. package/node_modules/mdream/bin/mdream.mjs +46 -0
  56. package/node_modules/mdream/dist/browser.d.mts +105 -0
  57. package/node_modules/mdream/dist/browser.mjs +262 -0
  58. package/node_modules/mdream/dist/edge.d.mts +100 -0
  59. package/node_modules/mdream/dist/edge.mjs +250 -0
  60. package/node_modules/mdream/dist/iife.js +605 -0
  61. package/node_modules/mdream/dist/index.d.mts +89 -0
  62. package/node_modules/mdream/dist/index.mjs +184 -0
  63. package/node_modules/mdream/dist/wasm.d.mts +100 -0
  64. package/node_modules/mdream/dist/wasm.mjs +140 -0
  65. package/node_modules/mdream/dist/worker.d.mts +101 -0
  66. package/node_modules/mdream/dist/worker.mjs +217 -0
  67. package/node_modules/mdream/napi/index.d.mts +127 -0
  68. package/node_modules/mdream/napi/index.d.ts +127 -0
  69. package/node_modules/mdream/napi/index.mjs +725 -0
  70. package/node_modules/mdream/napi/rust.android-arm-eabi.node +0 -0
  71. package/node_modules/mdream/napi/rust.android-arm64.node +0 -0
  72. package/node_modules/mdream/napi/rust.darwin-arm64.node +0 -0
  73. package/node_modules/mdream/napi/rust.darwin-x64.node +0 -0
  74. package/node_modules/mdream/napi/rust.freebsd-x64.node +0 -0
  75. package/node_modules/mdream/napi/rust.linux-arm-gnueabihf.node +0 -0
  76. package/node_modules/mdream/napi/rust.linux-arm64-gnu.node +0 -0
  77. package/node_modules/mdream/napi/rust.linux-arm64-musl.node +0 -0
  78. package/node_modules/mdream/napi/rust.linux-x64-gnu.node +0 -0
  79. package/node_modules/mdream/napi/rust.linux-x64-musl.node +0 -0
  80. package/node_modules/mdream/napi/rust.wasi.cjs +2144 -0
  81. package/node_modules/mdream/napi/rust.wasm32-wasi.wasm +0 -0
  82. package/node_modules/mdream/napi/rust.win32-arm64-msvc.node +0 -0
  83. package/node_modules/mdream/napi/rust.win32-x64-msvc.node +0 -0
  84. package/node_modules/mdream/node_modules/@emnapi/core/LICENSE +21 -0
  85. package/node_modules/mdream/node_modules/@emnapi/core/README.md +1 -0
  86. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.d.ts +392 -0
  87. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.full.d.ts +392 -0
  88. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.full.js +8351 -0
  89. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.js +7268 -0
  90. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/async-work.d.ts +5 -0
  91. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/async-work.js +843 -0
  92. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/index.d.ts +4 -0
  93. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/index.js +3 -0
  94. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/threadsafe-function.d.ts +5 -0
  95. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/threadsafe-function.js +1010 -0
  96. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/v8.d.ts +5 -0
  97. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/v8.js +1446 -0
  98. package/node_modules/mdream/node_modules/@emnapi/core/package.json +39 -0
  99. package/node_modules/mdream/node_modules/@emnapi/core/rollup.config.js +60 -0
  100. package/node_modules/mdream/node_modules/@emnapi/runtime/LICENSE +21 -0
  101. package/node_modules/mdream/node_modules/@emnapi/runtime/README.md +1 -0
  102. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.d.ts +833 -0
  103. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.js +2306 -0
  104. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.js.map +1 -0
  105. package/node_modules/mdream/node_modules/@emnapi/runtime/index.cjs +63 -0
  106. package/node_modules/mdream/node_modules/@emnapi/runtime/package.json +39 -0
  107. package/node_modules/mdream/node_modules/@emnapi/runtime/rollup.config.js +25 -0
  108. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/LICENSE +21 -0
  109. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/README.md +203 -0
  110. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.d.ts +236 -0
  111. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.js +1086 -0
  112. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/package.json +35 -0
  113. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/rollup.config.js +6 -0
  114. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +1472 -0
  115. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +1470 -0
  116. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +237 -0
  117. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/fs.js +18260 -0
  118. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +317 -0
  119. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/package.json +67 -0
  120. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/runtime.cjs +39 -0
  121. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/runtime.js +36 -0
  122. package/node_modules/mdream/node_modules/@tybys/wasm-util/LICENSE +21 -0
  123. package/node_modules/mdream/node_modules/@tybys/wasm-util/README.md +193 -0
  124. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/tsdoc-metadata.json +11 -0
  125. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.d.ts +423 -0
  126. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm-bundler.js +2932 -0
  127. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm.js +2932 -0
  128. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm.min.js +1 -0
  129. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.js +2954 -0
  130. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.min.js +1 -0
  131. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/asyncify.js +158 -0
  132. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/index.js +13 -0
  133. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/jspi.js +46 -0
  134. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/load.js +97 -0
  135. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/memory.js +35 -0
  136. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/error.js +103 -0
  137. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/fd.js +268 -0
  138. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/fs.js +3 -0
  139. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/index.js +192 -0
  140. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/path.js +316 -0
  141. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/preview1.js +1599 -0
  142. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/rights.js +141 -0
  143. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/types.js +220 -0
  144. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/util.js +128 -0
  145. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/webassembly.js +13 -0
  146. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/asyncify.mjs +153 -0
  147. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/index.mjs +9 -0
  148. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/jspi.mjs +39 -0
  149. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/load.mjs +89 -0
  150. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/memory.mjs +28 -0
  151. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/error.mjs +97 -0
  152. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/fd.mjs +256 -0
  153. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/fs.mjs +1 -0
  154. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/index.mjs +186 -0
  155. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/path.mjs +310 -0
  156. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/preview1.mjs +1593 -0
  157. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/rights.mjs +135 -0
  158. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/types.mjs +216 -0
  159. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/util.mjs +113 -0
  160. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/webassembly.mjs +9 -0
  161. package/node_modules/mdream/node_modules/@tybys/wasm-util/package.json +58 -0
  162. package/node_modules/mdream/node_modules/tslib/CopyrightNotice.txt +15 -0
  163. package/node_modules/mdream/node_modules/tslib/LICENSE.txt +12 -0
  164. package/node_modules/mdream/node_modules/tslib/README.md +164 -0
  165. package/node_modules/mdream/node_modules/tslib/SECURITY.md +41 -0
  166. package/node_modules/mdream/node_modules/tslib/modules/index.d.ts +38 -0
  167. package/node_modules/mdream/node_modules/tslib/modules/index.js +70 -0
  168. package/node_modules/mdream/node_modules/tslib/modules/package.json +3 -0
  169. package/node_modules/mdream/node_modules/tslib/package.json +47 -0
  170. package/node_modules/mdream/node_modules/tslib/tslib.d.ts +460 -0
  171. package/node_modules/mdream/node_modules/tslib/tslib.es6.html +1 -0
  172. package/node_modules/mdream/node_modules/tslib/tslib.es6.js +402 -0
  173. package/node_modules/mdream/node_modules/tslib/tslib.es6.mjs +401 -0
  174. package/node_modules/mdream/node_modules/tslib/tslib.html +1 -0
  175. package/node_modules/mdream/node_modules/tslib/tslib.js +484 -0
  176. package/node_modules/mdream/package.json +110 -0
  177. package/node_modules/mdream/skills/mdream/SKILL.md +124 -0
  178. package/node_modules/mdream/skills/mdream/references/runtimes.md +49 -0
  179. package/node_modules/mdream/wasm/mdream_edge.d.ts +90 -0
  180. package/node_modules/mdream/wasm/mdream_edge.js +517 -0
  181. package/node_modules/mdream/wasm/mdream_edge_bg.wasm +0 -0
  182. package/node_modules/mdream/wasm/mdream_edge_bg.wasm.d.ts +20 -0
  183. package/node_modules/mdream/wasm/package.json +17 -0
  184. package/node_modules/mdream/wasm-bundler/mdream_edge.d.ts +45 -0
  185. package/node_modules/mdream/wasm-bundler/mdream_edge.js +13 -0
  186. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.js +413 -0
  187. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.wasm +0 -0
  188. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.wasm.d.ts +20 -0
  189. package/node_modules/mdream/wasm-bundler/package.json +19 -0
  190. package/node_modules/pathe/LICENSE +70 -0
  191. package/node_modules/pathe/README.md +73 -0
  192. package/node_modules/pathe/dist/index.cjs +39 -0
  193. package/node_modules/pathe/dist/index.d.cts +47 -0
  194. package/node_modules/pathe/dist/index.d.mts +47 -0
  195. package/node_modules/pathe/dist/index.d.ts +47 -0
  196. package/node_modules/pathe/dist/index.mjs +19 -0
  197. package/node_modules/pathe/dist/shared/pathe.BSlhyZSM.cjs +266 -0
  198. package/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs +249 -0
  199. package/node_modules/pathe/dist/utils.cjs +82 -0
  200. package/node_modules/pathe/dist/utils.d.cts +32 -0
  201. package/node_modules/pathe/dist/utils.d.mts +32 -0
  202. package/node_modules/pathe/dist/utils.d.ts +32 -0
  203. package/node_modules/pathe/dist/utils.mjs +77 -0
  204. package/node_modules/pathe/package.json +61 -0
  205. package/node_modules/pathe/utils.d.ts +1 -0
  206. package/package.json +8 -64
@@ -0,0 +1,1091 @@
1
+ # mdream
2
+
3
+ [![npm version](https://img.shields.io/npm/v/mdream?color=yellow)](https://npmjs.com/package/mdream)
4
+ [![npm downloads](https://img.shields.io/npm/dm/mdream?color=yellow)](https://npm.chart.dev/mdream)
5
+ [![license](https://img.shields.io/github/license/harlan-zw/mdream?color=yellow)](https://github.com/harlan-zw/mdream/blob/main/LICENSE.md)
6
+ <a href="https://skilld.dev/gh/harlan-zw/mdream">
7
+ <picture>
8
+ <source media="(prefers-color-scheme: dark)" srcset="https://skilld.dev/b/harlan-zw/mdream?theme=dark">
9
+ <source media="(prefers-color-scheme: light)" srcset="https://skilld.dev/b/harlan-zw/mdream?theme=light">
10
+ <img alt="Skill repository on skilld.dev" src="https://skilld.dev/b/harlan-zw/mdream?theme=light">
11
+ </picture>
12
+ </a>
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # npm
18
+ npm install mdream
19
+
20
+ # pnpm
21
+ pnpm add mdream
22
+
23
+ # yarn
24
+ yarn add mdream
25
+ ```
26
+
27
+ > [!TIP]
28
+ > Using an AI agent? Get the mdream Skill on [skilld.dev/gh/harlan-zw/mdream](https://skilld.dev/gh/harlan-zw/mdream).
29
+
30
+ For the JavaScript-only engine (hook-based plugins, splitter, pure HTML parser):
31
+
32
+ ```bash
33
+ pnpm add @mdream/js
34
+ ```
35
+
36
+ ### Bundler Compatibility
37
+
38
+ The `mdream` package uses native Node.js bindings (NAPI-RS) which cannot be statically bundled. If your bundler fails to resolve `mdream`, mark it as external:
39
+
40
+ **Next.js / Turbopack:**
41
+ ```js
42
+ // next.config.js
43
+ const nextConfig = {
44
+ serverExternalPackages: ['mdream'],
45
+ }
46
+ ```
47
+
48
+ **Webpack / other bundlers:**
49
+ ```js
50
+ externals: ['mdream']
51
+ ```
52
+
53
+ > [!TIP]
54
+ > [`@mdream/js`](https://github.com/harlan-zw/mdream/tree/main/packages/js) has zero native dependencies and works with all bundlers without configuration.
55
+
56
+ > [!TIP]
57
+ > Using Vite? [`@mdream/vite`](https://github.com/harlan-zw/mdream/tree/main/packages/vite) handles this automatically.
58
+
59
+ ## Table of Contents
60
+
61
+ - [API Reference](#api-reference)
62
+ - [htmlToMarkdown()](#htmltomarkdown)
63
+ - [streamHtmlToMarkdown()](#streamhtmltomarkdown)
64
+ - [Engines](#engines)
65
+ - [Options](#options)
66
+ - [MdreamOptions (Rust engine)](#mdreamoptions-rust-engine)
67
+ - [MdreamOptions (JS engine)](#mdreamoptions-js-engine)
68
+ - [CleanOptions](#cleanoptions)
69
+ - [FrontmatterConfig](#frontmatterconfig)
70
+ - [TagOverride](#tagoverride)
71
+ - [FilterOptions](#filteroptions)
72
+ - [Presets](#presets)
73
+ - [Minimal Preset](#minimal-preset)
74
+ - [Built-in Plugins](#built-in-plugins)
75
+ - [Frontmatter](#frontmatter-plugin)
76
+ - [Isolate Main](#isolate-main-plugin)
77
+ - [Tailwind](#tailwind-plugin)
78
+ - [Filter](#filter-plugin)
79
+ - [Extraction](#extraction-plugin)
80
+ - [Hook-Based Plugins (JS Engine)](#hook-based-plugins-js-engine)
81
+ - [Plugin Hooks](#plugin-hooks)
82
+ - [createPlugin()](#createplugin)
83
+ - [Markdown Splitting (JS Engine)](#markdown-splitting-js-engine)
84
+ - [Basic Chunking](#basic-chunking)
85
+ - [Streaming Chunks](#streaming-chunks-memory-efficient)
86
+ - [Splitter Options](#splitter-options)
87
+ - [Chunk Metadata](#chunk-metadata)
88
+ - [Content Negotiation](#content-negotiation)
89
+ - [Pure HTML Parser (JS Engine)](#pure-html-parser-js-engine)
90
+ - [CLI Usage](#cli-usage)
91
+ - [Browser and Edge Usage](#browser-and-edge-usage)
92
+ - [Edge / Cloudflare Workers](#edge--cloudflare-workers)
93
+ - [Browser CDN (IIFE)](#browser-cdn-iife)
94
+ - [Web Worker](#web-worker)
95
+ - [llms.txt Generation](#llmstxt-generation)
96
+ - [Related Packages](#related-packages)
97
+
98
+ ## API Reference
99
+
100
+ ### `htmlToMarkdown()`
101
+
102
+ Converts a complete HTML string to Markdown, plain text, or HTML. It is synchronous in Node and on edge runtimes.
103
+
104
+ **Rust engine** (`mdream`):
105
+
106
+ ```ts
107
+ import { htmlToMarkdown } from 'mdream'
108
+
109
+ function htmlToMarkdown(html: string, options?: Partial<MdreamOptions>): string
110
+
111
+ // Browser bundles and the CDN script load the WASM binary first
112
+ function htmlToMarkdown(html: string, options?: Partial<MdreamOptions>): Promise<string>
113
+ ```
114
+
115
+ **JS engine** (`@mdream/js`):
116
+
117
+ ```ts
118
+ import { htmlToMarkdown } from '@mdream/js'
119
+
120
+ function htmlToMarkdown(html: string, options?: Partial<MdreamOptions>): string
121
+ ```
122
+
123
+ **Example:**
124
+
125
+ ```ts
126
+ import { htmlToMarkdown } from 'mdream'
127
+
128
+ const markdown = htmlToMarkdown('<h1>Hello World</h1><p>Some content.</p>')
129
+ // # Hello World
130
+ //
131
+ // Some content.
132
+
133
+ const text = htmlToMarkdown('<h1>Hello <strong>World</strong></h1>', {
134
+ format: 'text',
135
+ })
136
+ // Hello World
137
+
138
+ const html = htmlToMarkdown('<h1>Hello <strong>World</strong></h1>', {
139
+ format: 'html',
140
+ })
141
+ // <h1 id="hello-world">Hello <strong>World</strong></h1>
142
+ ```
143
+
144
+ ### `streamHtmlToMarkdown()`
145
+
146
+ Converts an HTML `ReadableStream` to Markdown, plain text, or HTML incrementally. Returns an `AsyncIterable<string>` that yields output chunks as they are processed.
147
+
148
+ It takes the same options as `htmlToMarkdown()`. The `frontmatter` callback and the `extraction` handlers run once, after the stream ends and before the last chunk is yielded.
149
+
150
+
151
+ ```ts
152
+ import { streamHtmlToMarkdown } from 'mdream'
153
+
154
+ function streamHtmlToMarkdown(
155
+ htmlStream: ReadableStream<Uint8Array | string> | null,
156
+ options?: Partial<MdreamOptions>,
157
+ ): AsyncIterable<string>
158
+ ```
159
+
160
+
161
+ **Example:**
162
+
163
+ ```ts
164
+ import { streamHtmlToMarkdown } from 'mdream'
165
+
166
+ const response = await fetch('https://example.com')
167
+ const stream = response.body
168
+
169
+ for await (const chunk of streamHtmlToMarkdown(stream, {
170
+ origin: 'https://example.com',
171
+ })) {
172
+ process.stdout.write(chunk)
173
+ }
174
+ ```
175
+
176
+ ## Engines
177
+
178
+ Mdream includes two rendering engines, automatically selecting the best one for your environment:
179
+
180
+ | Engine | Package | Plugins | Use case |
181
+ |--------|---------|---------|----------|
182
+ | **Rust** (NAPI) | `mdream` | Declarative config only | Node.js (default) |
183
+ | **Rust** (WASM) | `mdream` | Declarative config only | Edge, browser |
184
+ | **JavaScript** | `@mdream/js` | Hook-based + declarative | Custom plugins, splitter |
185
+
186
+ ```ts
187
+ // JavaScript engine (required for hook-based plugins)
188
+ import { htmlToMarkdown } from '@mdream/js'
189
+
190
+ // Rust NAPI engine (auto-selected in Node.js)
191
+ import { htmlToMarkdown } from 'mdream'
192
+ ```
193
+
194
+ Both engines support the same declarative plugins, but the option shape differs. The Rust engine takes `minimal`, `frontmatter`, `isolateMain`, `tailwind`, `filter`, `extraction`, and `tagOverrides` at the top level. The JS engine reads the plugins from `options.plugins` and has no `minimal` option: use `withMinimalPreset()` from `@mdream/js/preset/minimal`. If the JS engine gets one of these options at the top level, it throws a `TypeError` that names the fix. The JS engine also supports `hooks` for imperative plugin transforms.
195
+
196
+ ## Options
197
+
198
+ ### MdreamOptions (Rust engine)
199
+
200
+ Defined in `mdream`:
201
+
202
+ ```ts
203
+ interface MdreamOptions {
204
+ /** Base URL for resolving relative links and images. */
205
+ origin?: string
206
+
207
+ /**
208
+ * Enable minimal preset (frontmatter, isolateMain, tailwind, filter).
209
+ * Default: false
210
+ */
211
+ minimal?: boolean
212
+
213
+ /**
214
+ * Post-processing cleanup. Pass `true` for all cleanup, or an object for specific features.
215
+ * Enabled by default when `minimal` is true.
216
+ */
217
+ clean?: boolean | CleanOptions
218
+
219
+ /**
220
+ * Extract frontmatter from HTML <head>.
221
+ * - `true`: enable with defaults
222
+ * - `(fm) => void`: enable and receive structured data via callback
223
+ * - `FrontmatterConfig`: enable with config and optional callback
224
+ */
225
+ frontmatter?: boolean | ((frontmatter: Record<string, string>) => void) | FrontmatterConfig
226
+
227
+ /** Isolate main content area. Default when minimal: true */
228
+ isolateMain?: boolean
229
+
230
+ /** Convert Tailwind utility classes to Markdown. Default when minimal: true */
231
+ tailwind?: boolean
232
+
233
+ /** Filter elements by CSS selectors. Default when minimal: excludes form, nav, footer, etc. */
234
+ filter?: false | { include?: string[], exclude?: string[], processChildren?: boolean }
235
+
236
+ /** Extract elements matching CSS selectors during conversion. */
237
+ extraction?: Record<string, (element: ExtractedElement) => void>
238
+
239
+ /** Override tag rendering behavior. String values act as aliases. */
240
+ tagOverrides?: Record<string, TagOverride | string>
241
+
242
+ /**
243
+ * Hard-wrap prose at this many characters, breaking on word boundaries.
244
+ * Applied inline during conversion (zero-cost when unset). Code blocks,
245
+ * tables, and headings are never wrapped. `0` (or unset) disables wrapping.
246
+ */
247
+ wrapWidth?: number
248
+
249
+ /** Output Markdown, plain text, or HTML. Default: 'markdown' */
250
+ format?: 'markdown' | 'text' | 'html'
251
+ }
252
+ ```
253
+
254
+ ### MdreamOptions (JS engine)
255
+
256
+ The JS engine extends the shared `EngineOptions` with hook-based plugin support:
257
+
258
+ ```ts
259
+ interface MdreamOptions extends EngineOptions {
260
+ /** Imperative hook-based transform plugins. JS engine only. */
261
+ hooks?: TransformPlugin[]
262
+ }
263
+
264
+ interface EngineOptions {
265
+ origin?: string
266
+ clean?: boolean | CleanOptions
267
+ plugins?: BuiltinPlugins
268
+
269
+ /**
270
+ * Hard-wrap prose at this many characters, breaking on word boundaries.
271
+ * Code blocks, tables, and headings are never wrapped. `0` (or unset)
272
+ * disables wrapping.
273
+ */
274
+ wrapWidth?: number
275
+
276
+ /** Output Markdown, plain text, or HTML. Default: 'markdown' */
277
+ format?: 'markdown' | 'text' | 'html'
278
+ }
279
+
280
+ interface BuiltinPlugins {
281
+ filter?: false | { include?: (string | number)[], exclude?: (string | number)[], processChildren?: boolean }
282
+ frontmatter?: boolean | ((fm: Record<string, string>) => void) | FrontmatterConfig
283
+ isolateMain?: boolean
284
+ tailwind?: boolean
285
+ extraction?: Record<string, (element: ExtractedElement) => void>
286
+ tagOverrides?: Record<string, TagOverride | string>
287
+ }
288
+ ```
289
+
290
+ Note: The JS engine uses `options.plugins.filter` while the Rust engine uses `options.filter` directly.
291
+
292
+ ### CleanOptions
293
+
294
+ Post-processing cleanup applied to the final Markdown output. All options default to `false` unless `clean: true` is set.
295
+
296
+ ```ts
297
+ interface CleanOptions {
298
+ /** Strip tracking query parameters (utm_*, fbclid, gclid, etc.) from URLs */
299
+ urls?: boolean
300
+ /** Strip fragment-only links that don't match any heading in the output */
301
+ fragments?: boolean
302
+ /** Strip links with meaningless hrefs (#, javascript:void(0)) to plain text */
303
+ emptyLinks?: boolean
304
+ /** Collapse 3+ consecutive blank lines to 2 */
305
+ blankLines?: boolean
306
+ /** Strip links where text equals URL: [https://x.com](https://x.com) becomes https://x.com */
307
+ redundantLinks?: boolean
308
+ /** Strip self-referencing heading anchors: ## [Title](#title) becomes ## Title */
309
+ selfLinkHeadings?: boolean
310
+ /** Strip images with no alt text (decorative/tracking pixels) */
311
+ emptyImages?: boolean
312
+ /** Drop links that produce no visible text: [](url) is removed entirely */
313
+ emptyLinkText?: boolean
314
+ }
315
+ ```
316
+
317
+ **Example:**
318
+
319
+ ```ts
320
+ const markdown = htmlToMarkdown(html, {
321
+ clean: {
322
+ urls: true,
323
+ emptyLinks: true,
324
+ emptyImages: true,
325
+ },
326
+ })
327
+ ```
328
+
329
+ ### FrontmatterConfig
330
+
331
+ ```ts
332
+ interface FrontmatterConfig {
333
+ /** Additional static fields to include in frontmatter */
334
+ additionalFields?: Record<string, string>
335
+ /**
336
+ * Meta tag names to extract beyond the defaults.
337
+ * Defaults: description, keywords, author, date,
338
+ * og:title, og:description, twitter:title, twitter:description
339
+ */
340
+ metaFields?: string[]
341
+ /** Callback to receive structured frontmatter data after conversion */
342
+ onExtract?: (frontmatter: Record<string, string>) => void
343
+ }
344
+ ```
345
+
346
+ ### TagOverride
347
+
348
+ Override how specific HTML tags are rendered in Markdown. String values act as aliases.
349
+
350
+ > **Unknown tags pass through as plain text.** Tag matching is strict: only the standard HTML tags ship with built-in Markdown semantics. Custom elements (`<my-widget>`), web components, and any non-standard tag emit their text content verbatim, with the surrounding tag dropped. To render a custom tag with Markdown semantics, alias it with `tagOverrides`:
351
+ >
352
+ > ```ts
353
+ > htmlToMarkdown('<my-em>hi</my-em>', { tagOverrides: { 'my-em': 'em' } })
354
+ > // → "*hi*"
355
+ > ```
356
+
357
+ ```ts
358
+ interface TagOverride {
359
+ /** Markdown string to insert when entering this tag */
360
+ enter?: string
361
+ /** Markdown string to insert when exiting this tag */
362
+ exit?: string
363
+ /** Spacing: [newlines before, newlines after] */
364
+ spacing?: number[]
365
+ /** Whether this tag should be treated as inline */
366
+ isInline?: boolean
367
+ /** Whether this tag is self-closing */
368
+ isSelfClosing?: boolean
369
+ /** Whether whitespace inside this tag should be collapsed */
370
+ collapsesInnerWhiteSpace?: boolean
371
+ /** Alias this tag to another tag's handler */
372
+ alias?: string
373
+ }
374
+ ```
375
+
376
+ **Example:**
377
+
378
+ ```ts
379
+ const markdown = htmlToMarkdown(html, {
380
+ tagOverrides: {
381
+ // Treat <x-heading> like <h2>
382
+ 'x-heading': 'h2',
383
+ // Custom rendering for <callout>
384
+ 'callout': {
385
+ enter: '> **Note:** ',
386
+ exit: '',
387
+ spacing: [2, 2],
388
+ },
389
+ },
390
+ })
391
+ ```
392
+
393
+ **Output is GitHub Flavored Markdown.** Mdream emits a fixed GFM dialect tuned for LLM input: ATX headings (`#`), fenced code blocks (` ``` `), `-` bullets, `*` emphasis, `**` strong, `---` horizontal rules, inline links. These are not configurable. For simple delimiter swaps you can use `tagOverrides`:
394
+
395
+ ```ts
396
+ htmlToMarkdown(html, {
397
+ tagOverrides: {
398
+ em: { enter: '_', exit: '_', isInline: true }, // *x* → _x_
399
+ strong: { enter: '__', exit: '__', isInline: true }, // **x** → __x__
400
+ hr: { enter: '* * *', exit: '' }, // --- → * * *
401
+ },
402
+ })
403
+ ```
404
+
405
+ Structural style differences (setext headings, indented code blocks, reference-style links, `~~~` fences, dynamic list markers) are out of scope. If you need turndown-style configurability, use [turndown](https://github.com/mixmark-io/turndown). If you have a use case for these in mdream, please open an issue.
406
+
407
+ ### FilterOptions
408
+
409
+ ```ts
410
+ interface FilterOptions {
411
+ /** CSS selectors, tag names, or TAG_* constants for elements to include (all others excluded) */
412
+ include?: (string | number)[]
413
+ /** CSS selectors, tag names, or TAG_* constants for elements to exclude */
414
+ exclude?: (string | number)[]
415
+ /** Whether to also process children of matched elements. Default: true */
416
+ processChildren?: boolean
417
+ }
418
+ ```
419
+
420
+ ## Presets
421
+
422
+ ### Minimal Preset
423
+
424
+ The `minimal` preset enables the following plugins together:
425
+
426
+ - **frontmatter**: Extracts metadata from HTML `<head>` into YAML frontmatter
427
+ - **isolateMain**: Extracts the main content area, skipping navigation, headers, and footers
428
+ - **tailwind**: Converts Tailwind utility classes to Markdown formatting
429
+ - **filter**: Excludes `form`, `fieldset`, `object`, `embed`, `footer`, `aside`, `iframe`, `input`, `textarea`, `select`, `button`, `nav`
430
+ - **clean**: All post-processing cleanup enabled
431
+
432
+ A `filter` passed with `minimal` adds to the preset's excludes. It does not replace them. To turn the preset's filter off, pass `filter: false`. `withMinimalPreset()` in the JS engine works the same way.
433
+
434
+ ```ts
435
+ // Excludes h1 as well as form, nav, footer, and the rest
436
+ htmlToMarkdown(html, { minimal: true, filter: { exclude: ['h1'] } })
437
+
438
+ // Keeps forms and nav
439
+ htmlToMarkdown(html, { minimal: true, filter: false })
440
+ ```
441
+
442
+ **Rust engine:**
443
+
444
+ ```ts
445
+ import { htmlToMarkdown } from 'mdream'
446
+
447
+ const markdown = htmlToMarkdown(html, {
448
+ origin: 'https://example.com',
449
+ minimal: true,
450
+ })
451
+ ```
452
+
453
+ **JS engine (using `withMinimalPreset`):**
454
+
455
+ ```ts
456
+ import { htmlToMarkdown } from '@mdream/js'
457
+ import { withMinimalPreset } from '@mdream/js/preset/minimal'
458
+
459
+ const markdown = htmlToMarkdown(html, withMinimalPreset({
460
+ origin: 'https://example.com',
461
+ }))
462
+ ```
463
+
464
+ `withMinimalPreset()` returns an `EngineOptions` object with all plugin defaults applied. You can override individual plugins. A `filter` adds to the preset's excludes:
465
+
466
+ ```ts
467
+ const markdown = htmlToMarkdown(html, withMinimalPreset({
468
+ plugins: {
469
+ frontmatter: false,
470
+ filter: { exclude: ['.cookie-banner'] },
471
+ },
472
+ }))
473
+ ```
474
+
475
+ ## Built-in Plugins
476
+
477
+ All built-in plugins work with both the Rust and JS engines through declarative configuration.
478
+
479
+ ### Frontmatter Plugin
480
+
481
+ Extracts metadata from the HTML `<head>` element and generates YAML frontmatter.
482
+
483
+ **Extracted fields by default:** `title`, `description`, `keywords`, `author`, `date`, `og:title`, `og:description`, `twitter:title`, `twitter:description`.
484
+
485
+ ```ts
486
+ // Enable with defaults
487
+ htmlToMarkdown(html, { frontmatter: true })
488
+
489
+ // With callback to receive structured data
490
+ htmlToMarkdown(html, {
491
+ frontmatter: (fm) => {
492
+ console.log(fm.title)
493
+ console.log(fm.description)
494
+ },
495
+ })
496
+
497
+ // With full config
498
+ htmlToMarkdown(html, {
499
+ frontmatter: {
500
+ additionalFields: { source: 'https://example.com' },
501
+ metaFields: ['robots', 'viewport'],
502
+ onExtract: fm => console.log(fm),
503
+ },
504
+ })
505
+ ```
506
+
507
+ **Output example:**
508
+
509
+ ```yaml
510
+ ---
511
+ title: My Page Title
512
+ meta:
513
+ description: A page description
514
+ 'og:title': My Page Title
515
+ ---
516
+ ```
517
+
518
+ ### Isolate Main Plugin
519
+
520
+ Isolates the main content area using the following priority:
521
+
522
+ 1. If an explicit `<main>` element exists (within 5 depth levels), use its content exclusively
523
+ 2. Otherwise, find content between the first header tag (`h1`-`h6`) and the first `<footer>`
524
+ 3. Headings inside `<header>` tags are skipped during fallback detection
525
+ 4. The `<head>` section is always passed through for other plugins (e.g., frontmatter)
526
+
527
+ ```ts
528
+ htmlToMarkdown(html, { isolateMain: true })
529
+ ```
530
+
531
+ ### Tailwind Plugin
532
+
533
+ Converts Tailwind CSS utility classes to semantic Markdown formatting:
534
+
535
+ | Tailwind Class | Markdown Output |
536
+ |---|---|
537
+ | `font-bold`, `font-semibold`, `font-medium`, `font-extrabold`, `font-black` | `**bold**` |
538
+ | `italic`, `font-italic` | `*italic*` |
539
+ | `line-through` | `~~strikethrough~~` |
540
+ | `hidden`, `invisible` | Content removed |
541
+ | `absolute`, `fixed`, `sticky` | Content removed |
542
+
543
+ Supports responsive breakpoint prefixes (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`) with mobile-first resolution.
544
+
545
+ ```ts
546
+ htmlToMarkdown(html, { tailwind: true })
547
+ ```
548
+
549
+ ### Filter Plugin
550
+
551
+ Filters HTML elements by CSS selectors, tag names, or `TAG_*` constants.
552
+
553
+ ```ts
554
+ // Exclude navigation, sidebar, footer
555
+ htmlToMarkdown(html, {
556
+ filter: {
557
+ exclude: ['nav', '#sidebar', '.footer', 'aside'],
558
+ },
559
+ })
560
+
561
+ // Include only specific elements
562
+ htmlToMarkdown(html, {
563
+ filter: {
564
+ include: ['article', 'main'],
565
+ },
566
+ })
567
+ ```
568
+
569
+ The JS engine also supports `TAG_*` integer constants for filtering:
570
+
571
+ ```ts
572
+ import { TAG_FOOTER, TAG_NAV } from '@mdream/js'
573
+
574
+ htmlToMarkdown(html, {
575
+ plugins: {
576
+ filter: { exclude: [TAG_NAV, TAG_FOOTER] },
577
+ },
578
+ })
579
+ ```
580
+
581
+ Elements with `style="position: absolute"` or `style="position: fixed"` are also automatically excluded when the filter plugin is active.
582
+
583
+ ### Extraction Plugin
584
+
585
+ Extracts elements matching CSS selectors during conversion. Callbacks receive the matched element with its accumulated text content and attributes.
586
+
587
+ ```ts
588
+ htmlToMarkdown(html, {
589
+ extraction: {
590
+ 'h2': (el) => {
591
+ console.log('Heading:', el.textContent)
592
+ },
593
+ 'img[alt]': (el) => {
594
+ console.log('Image:', el.attributes.src, el.attributes.alt)
595
+ },
596
+ 'a[href]': (el) => {
597
+ console.log('Link:', el.textContent, el.attributes.href)
598
+ },
599
+ },
600
+ })
601
+ ```
602
+
603
+ The `ExtractedElement` interface:
604
+
605
+ ```ts
606
+ interface ExtractedElement {
607
+ selector: string
608
+ tagName: string
609
+ textContent: string
610
+ attributes: Record<string, string>
611
+ }
612
+ ```
613
+
614
+ ## Hook-Based Plugins (JS Engine)
615
+
616
+ The JS engine (`@mdream/js`) supports imperative hook-based plugins for custom transform logic. These allow you to intercept and modify the conversion pipeline at multiple stages.
617
+
618
+ ```ts
619
+ import { htmlToMarkdown } from '@mdream/js'
620
+ import { createPlugin } from '@mdream/js/plugins'
621
+
622
+ const myPlugin = createPlugin({
623
+ onNodeEnter(node) {
624
+ if (node.name === 'h1')
625
+ return '** '
626
+ },
627
+ processTextNode(textNode) {
628
+ if (textNode.parent?.attributes?.id === 'highlight') {
629
+ return { content: `**${textNode.value}**`, skip: false }
630
+ }
631
+ },
632
+ })
633
+
634
+ const markdown = htmlToMarkdown(html, { hooks: [myPlugin] })
635
+ ```
636
+
637
+ ### Plugin Hooks
638
+
639
+ ```ts
640
+ interface TransformPlugin {
641
+ /**
642
+ * Called before any node processing. Return { skip: true } to skip the node.
643
+ */
644
+ beforeNodeProcess?: (
645
+ event: NodeEvent,
646
+ state: MdreamRuntimeState,
647
+ ) => undefined | void | { skip: boolean }
648
+
649
+ /**
650
+ * Called when entering an element node.
651
+ * Return a string to prepend to the output.
652
+ */
653
+ onNodeEnter?: (
654
+ node: ElementNode,
655
+ state: MdreamRuntimeState,
656
+ ) => string | undefined | void
657
+
658
+ /**
659
+ * Called when exiting an element node.
660
+ * Return a string to append to the output.
661
+ */
662
+ onNodeExit?: (
663
+ node: ElementNode,
664
+ state: MdreamRuntimeState,
665
+ ) => string | undefined | void
666
+
667
+ /**
668
+ * Called to process element attributes (e.g., extracting Tailwind classes).
669
+ */
670
+ processAttributes?: (
671
+ node: ElementNode,
672
+ state: MdreamRuntimeState,
673
+ ) => void
674
+
675
+ /**
676
+ * Called for each text node. Return { content, skip } to transform text.
677
+ * Return undefined for no transformation.
678
+ */
679
+ processTextNode?: (
680
+ node: TextNode,
681
+ state: MdreamRuntimeState,
682
+ ) => { content: string, skip: boolean } | undefined
683
+ }
684
+ ```
685
+
686
+ ### `createPlugin()`
687
+
688
+ A typed identity function for creating plugins with full TypeScript inference:
689
+
690
+ ```ts
691
+ import { createPlugin } from '@mdream/js/plugins'
692
+
693
+ const plugin = createPlugin({
694
+ beforeNodeProcess({ node }) {
695
+ // Skip all div elements with class "ad"
696
+ if (node.type === 1 && node.attributes?.class?.includes('ad')) {
697
+ return { skip: true }
698
+ }
699
+ },
700
+ })
701
+ ```
702
+
703
+ ### Built-in Plugin Functions (JS Engine)
704
+
705
+ The following plugin factory functions are available from `@mdream/js/plugins`:
706
+
707
+ ```ts
708
+ import {
709
+ createPlugin,
710
+ extractionCollectorPlugin,
711
+ extractionPlugin,
712
+ filterPlugin,
713
+ frontmatterPlugin,
714
+ isolateMainPlugin,
715
+ tailwindPlugin,
716
+ } from '@mdream/js/plugins'
717
+ ```
718
+
719
+ ## Markdown Splitting (JS Engine)
720
+
721
+ Split HTML into Markdown chunks during conversion. Compatible with the LangChain `Document` structure.
722
+
723
+ Available from `@mdream/js/splitter`.
724
+
725
+ ### Basic Chunking
726
+
727
+ ```ts
728
+ import { TAG_H2 } from '@mdream/js'
729
+ import { htmlToMarkdownSplitChunks } from '@mdream/js/splitter'
730
+
731
+ const html = `
732
+ <h1>Documentation</h1>
733
+ <h2>Installation</h2>
734
+ <p>Install via npm...</p>
735
+ <h2>Usage</h2>
736
+ <p>Use it like this...</p>
737
+ `
738
+
739
+ const chunks = htmlToMarkdownSplitChunks(html, {
740
+ headersToSplitOn: [TAG_H2],
741
+ chunkSize: 1000,
742
+ chunkOverlap: 200,
743
+ stripHeaders: true,
744
+ })
745
+
746
+ chunks.forEach((chunk) => {
747
+ console.log(chunk.content)
748
+ console.log(chunk.metadata.headers) // { h1: "Documentation", h2: "Installation" }
749
+ console.log(chunk.metadata.code) // Language if chunk contains code
750
+ console.log(chunk.metadata.loc) // { lines: { from: 1, to: 5 } }
751
+ })
752
+ ```
753
+
754
+ ### Streaming Chunks (Memory Efficient)
755
+
756
+ For large documents, use the generator version to process chunks one at a time:
757
+
758
+ ```ts
759
+ import { htmlToMarkdownSplitChunksStream } from '@mdream/js/splitter'
760
+
761
+ for (const chunk of htmlToMarkdownSplitChunksStream(html, options)) {
762
+ await processChunk(chunk)
763
+
764
+ // Early termination supported
765
+ if (foundTarget)
766
+ break
767
+ }
768
+ ```
769
+
770
+ ### Splitter Options
771
+
772
+ ```ts
773
+ interface SplitterOptions {
774
+ // --- Structural splitting ---
775
+
776
+ /**
777
+ * Header tag IDs to split on (TAG_H1 through TAG_H6).
778
+ * Default: [TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6]
779
+ */
780
+ headersToSplitOn?: number[]
781
+
782
+ // --- Size-based splitting ---
783
+
784
+ /** Maximum chunk size in characters. Default: 1000 */
785
+ chunkSize?: number
786
+
787
+ /** Overlap between chunks for context preservation. Default: 200 */
788
+ chunkOverlap?: number
789
+
790
+ /**
791
+ * Custom length function (e.g., a token counter for LLM applications).
792
+ * Default: (text) => text.length
793
+ */
794
+ lengthFunction?: (text: string) => number
795
+
796
+ // --- Output formatting ---
797
+
798
+ /** Remove headers from chunk content. Default: true */
799
+ stripHeaders?: boolean
800
+
801
+ /** Split into individual lines. Default: false */
802
+ returnEachLine?: boolean
803
+
804
+ /** Keep separators in the split chunks. Default: false */
805
+ keepSeparator?: boolean
806
+
807
+ // --- Standard options ---
808
+
809
+ /** Base URL for resolving relative links/images */
810
+ origin?: string
811
+
812
+ /** Declarative built-in plugin config */
813
+ plugins?: BuiltinPlugins
814
+
815
+ /** Hook-based plugins (JS engine only) */
816
+ hooks?: TransformPlugin[]
817
+
818
+ /** Post-processing cleanup */
819
+ clean?: boolean | CleanOptions
820
+ }
821
+ ```
822
+
823
+ ### Chunk Metadata
824
+
825
+ Each chunk includes metadata for context:
826
+
827
+ ```ts
828
+ interface MarkdownChunk {
829
+ content: string
830
+ metadata: {
831
+ /** Header hierarchy at this chunk position */
832
+ headers?: Record<string, string> // { h1: "Title", h2: "Section" }
833
+ /** Code block language if chunk contains code */
834
+ code?: string
835
+ /** Line number range in the original document */
836
+ loc?: {
837
+ lines: { from: number, to: number }
838
+ }
839
+ }
840
+ }
841
+ ```
842
+
843
+ ### Use with Presets
844
+
845
+ Combine splitting with presets:
846
+
847
+ ```ts
848
+ import { TAG_H2 } from '@mdream/js'
849
+ import { withMinimalPreset } from '@mdream/js/preset/minimal'
850
+ import { htmlToMarkdownSplitChunks } from '@mdream/js/splitter'
851
+
852
+ const chunks = htmlToMarkdownSplitChunks(html, withMinimalPreset({
853
+ headersToSplitOn: [TAG_H2],
854
+ chunkSize: 500,
855
+ origin: 'https://example.com',
856
+ }))
857
+ ```
858
+
859
+ ## Content Negotiation
860
+
861
+ The `@mdream/js/negotiate` module provides HTTP content negotiation utilities for serving Markdown to LLM clients:
862
+
863
+ ```ts
864
+ import { parseAcceptHeader, shouldServeMarkdown } from '@mdream/js/negotiate'
865
+
866
+ // Check if client prefers markdown
867
+ const serveMarkdown = shouldServeMarkdown(
868
+ request.headers.get('accept'),
869
+ request.headers.get('sec-fetch-dest'),
870
+ )
871
+
872
+ if (serveMarkdown) {
873
+ return new Response(markdown, {
874
+ headers: { 'Content-Type': 'text/markdown' },
875
+ })
876
+ }
877
+ ```
878
+
879
+ `shouldServeMarkdown()` uses Accept header quality weights and position ordering. It returns `true` when `text/markdown` or `text/plain` has higher priority than `text/html`. Browser navigation requests (`sec-fetch-dest: document`) always return `false`.
880
+
881
+ ## Pure HTML Parser (JS Engine)
882
+
883
+ If you only need to parse HTML into a DOM-like event stream without converting to Markdown, use `parseHtml` from the JS engine:
884
+
885
+ ```ts
886
+ import { parseHtml } from '@mdream/js/parse'
887
+
888
+ const html = '<div><h1>Title</h1><p>Content</p></div>'
889
+ const { events, remainingHtml } = parseHtml(html)
890
+
891
+ events.forEach((event) => {
892
+ if (event.type === 0 && event.node.type === 1) { // Enter + Element
893
+ console.log('Entering element:', event.node.name)
894
+ }
895
+ })
896
+ ```
897
+
898
+ The parser provides:
899
+ - Pure AST event stream with no markdown generation overhead
900
+ - Enter/exit events for each element and text node
901
+ - Plugin support during parsing
902
+ - Streaming compatible via `parseHtmlStream()`
903
+
904
+ ## CLI Usage
905
+
906
+ Mdream provides a CLI that works with Unix pipes.
907
+
908
+ **Pipe site to Markdown:**
909
+
910
+ ```bash
911
+ curl -s https://en.wikipedia.org/wiki/Markdown \
912
+ | npx mdream --origin https://en.wikipedia.org --preset minimal \
913
+ | tee output.md
914
+ ```
915
+
916
+ **Local file to Markdown:**
917
+
918
+ ```bash
919
+ cat index.html \
920
+ | npx mdream --preset minimal \
921
+ | tee output.md
922
+ ```
923
+
924
+ **Plain text output:**
925
+
926
+ ```bash
927
+ cat index.html \
928
+ | npx mdream --format text \
929
+ | tee output.txt
930
+ ```
931
+
932
+ **HTML output:**
933
+
934
+ ```bash
935
+ cat index.html \
936
+ | npx mdream --format html \
937
+ | tee output.html
938
+ ```
939
+
940
+ ### CLI Options
941
+
942
+ | Option | Description |
943
+ |--------|-------------|
944
+ | `--origin <url>` | Base URL for resolving relative links and images |
945
+ | `--preset minimal` | Enable the minimal preset |
946
+ | `--wrap-width <n>` | Hard-wrap prose at `n` characters (code, tables, and headings are never wrapped) |
947
+ | `--format <format>` | Output format: `markdown`, `text`, `html` |
948
+ | `--text` | Alias for `--format text` |
949
+ | `-h`, `--help` | Display help information |
950
+
951
+ The CLI reads HTML from stdin and writes Markdown, plain text, or HTML to stdout. It uses the streaming API internally.
952
+
953
+ ## Browser and Edge Usage
954
+
955
+ Every entry takes the same `MdreamOptions` and produces the same Markdown string. In Node and edge runtimes, `htmlToMarkdown` is synchronous. In browser bundles, the CDN script, and `mdream/worker`, it returns `Promise<string>`, because the WASM binary loads first. Each export condition ships its own types, so TypeScript shows the right return type when it resolves the `browser` condition (for example, with `customConditions: ["browser"]`).
956
+
957
+ ```ts
958
+ import { htmlToMarkdown } from 'mdream'
959
+
960
+ // In a browser bundle
961
+ const markdown = await htmlToMarkdown('<h1>Hello</h1>', { minimal: true })
962
+ ```
963
+
964
+ ### Edge / Cloudflare Workers
965
+
966
+ For edge runtimes (Cloudflare Workers, Vercel Edge), `mdream` automatically selects the WASM build via export conditions (`workerd`, `edge-light`). Both `htmlToMarkdown` and `streamHtmlToMarkdown` are available:
967
+
968
+ ```ts
969
+ import { htmlToMarkdown, streamHtmlToMarkdown } from 'mdream'
970
+
971
+ // WASM engine auto-selected via export conditions
972
+ const markdown = htmlToMarkdown('<h1>Hello World</h1>')
973
+
974
+ // Streaming works the same as Node.js
975
+ const response = await fetch('https://example.com')
976
+ for await (const chunk of streamHtmlToMarkdown(response.body)) {
977
+ // process chunk
978
+ }
979
+ ```
980
+
981
+ Conversion errors are catchable. WASM has no unwinding, so an internal Rust panic aborts the call, but the message is preserved and re-thrown as a normal `Error` (with the raw WASM trap as `cause`), and the instance keeps working for later requests:
982
+
983
+ ```ts
984
+ try {
985
+ return new Response(htmlToMarkdown(html))
986
+ }
987
+ catch (error) {
988
+ // "mdream WASM panic, please report this at ...\npanicked at ..."
989
+ console.error(error)
990
+ return new Response('conversion failed', { status: 500 })
991
+ }
992
+ ```
993
+
994
+ If your toolchain doesn't resolve the export conditions, the wasm-bindgen build (web target) is exposed at `mdream/wasm` for manual initialization. Its `htmlToMarkdown` takes the same `MdreamOptions` as the `mdream` entry. Its `MarkdownStream` runs the callbacks in `finish()`.
995
+
996
+ ```ts
997
+ import init, { htmlToMarkdown } from 'mdream/wasm'
998
+ import wasmModule from 'mdream/wasm/mdream_edge_bg.wasm'
999
+
1000
+ await init({ module_or_path: wasmModule })
1001
+ const markdown = htmlToMarkdown('<h1>Hello</h1>', { minimal: true })
1002
+ ```
1003
+
1004
+ `mdream/worker` is not an edge entry. It runs the conversion in a browser Web Worker; see [Web Worker](#web-worker).
1005
+
1006
+ ### Browser CDN (IIFE)
1007
+
1008
+ Use mdream directly via CDN with no build step. The script inlines the WASM binary and initializes it on load, so `window.mdream.htmlToMarkdown()` is ready at once. It takes the same `MdreamOptions` as the `mdream` entry and returns `Promise<string>`, the same as the browser bundle.
1009
+
1010
+ ```html
1011
+ <script src="https://unpkg.com/mdream/dist/iife.js"></script>
1012
+ <script>
1013
+ window.mdream.htmlToMarkdown('<h1>Hello</h1><p>World</p>')
1014
+ .then(markdown => console.log(markdown)) // # Hello\n\nWorld
1015
+ </script>
1016
+ ```
1017
+
1018
+ **CDN Options:**
1019
+ - **unpkg**: `https://unpkg.com/mdream/dist/iife.js`
1020
+ - **jsDelivr**: `https://cdn.jsdelivr.net/npm/mdream/dist/iife.js`
1021
+
1022
+ ### Web Worker
1023
+
1024
+ For browser environments, `mdream/worker` runs conversions off the main thread using a Web Worker:
1025
+
1026
+ ```ts
1027
+ import { htmlToMarkdown, initWorker, terminateWorker } from 'mdream/worker'
1028
+
1029
+ await initWorker('/path/to/mdream_edge_bg.wasm')
1030
+
1031
+ // Takes the same options as the mdream entry. Callbacks run on this thread.
1032
+ const markdown = await htmlToMarkdown('<h1>Hello</h1>', { minimal: true })
1033
+
1034
+ // Clean up
1035
+ terminateWorker()
1036
+ ```
1037
+
1038
+ ## Content Extraction with Readability
1039
+
1040
+ For advanced content extraction (article detection, boilerplate removal), use [@mozilla/readability](https://github.com/mozilla/readability) before mdream:
1041
+
1042
+ ```ts
1043
+ import { Readability } from '@mozilla/readability'
1044
+ import { JSDOM } from 'jsdom'
1045
+ import { htmlToMarkdown } from 'mdream'
1046
+
1047
+ const dom = new JSDOM(html, { url: 'https://example.com' })
1048
+ const article = new Readability(dom.window.document).parse()
1049
+
1050
+ if (article) {
1051
+ const markdown = htmlToMarkdown(article.content)
1052
+ // article.title, article.excerpt, article.byline also available
1053
+ }
1054
+ ```
1055
+
1056
+ ## llms.txt Generation
1057
+
1058
+ For llms.txt artifact generation, use `@mdream/js/llms-txt` from the `@mdream/js` package. It accepts pre-converted Markdown and generates `llms.txt` and `llms-full.txt` artifacts.
1059
+
1060
+ ```ts
1061
+ import { generateLlmsTxtArtifacts } from '@mdream/js/llms-txt'
1062
+ import { htmlToMarkdown } from 'mdream'
1063
+
1064
+ const result = await generateLlmsTxtArtifacts({
1065
+ files: [
1066
+ { title: 'Home', url: '/', content: htmlToMarkdown(homeHtml) },
1067
+ { title: 'About', url: '/about', content: htmlToMarkdown(aboutHtml) },
1068
+ ],
1069
+ siteName: 'My Site',
1070
+ origin: 'https://example.com',
1071
+ generateFull: true,
1072
+ })
1073
+
1074
+ console.log(result.llmsTxt) // llms.txt content
1075
+ console.log(result.llmsFullTxt) // llms-full.txt content
1076
+ ```
1077
+
1078
+ ## Related Packages
1079
+
1080
+ | Package | Description |
1081
+ |---------|-------------|
1082
+ | [`mdream`](https://npmjs.com/package/mdream) | Core HTML to Markdown converter (Rust + WASM engine) |
1083
+ | [`@mdream/js`](https://npmjs.com/package/@mdream/js) | JavaScript engine with hook-based plugins, splitter, and llms.txt generation (`@mdream/js/llms-txt`) |
1084
+ | [`@mdream/crawl`](https://github.com/harlan-zw/mdream/tree/main/packages/crawl) | Site-wide crawler for llms.txt generation |
1085
+ | [`@mdream/vite`](https://github.com/harlan-zw/mdream/tree/main/packages/vite) | Vite plugin integration |
1086
+ | [`@mdream/nuxt`](https://github.com/harlan-zw/mdream/tree/main/packages/nuxt) | Nuxt module integration |
1087
+ | [`@mdream/action`](https://github.com/harlan-zw/mdream/tree/main/packages/action) | GitHub Actions integration |
1088
+
1089
+ ## License
1090
+
1091
+ Licensed under the [MIT license](https://github.com/harlan-zw/mdream/blob/main/LICENSE.md).