nuxt-ai-ready 2.5.3 → 3.0.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 (286) hide show
  1. package/README.md +13 -12
  2. package/dist/chunks/agent-skills.mjs +35 -12
  3. package/dist/chunks/prerender.mjs +35 -24
  4. package/dist/cli.mjs +5 -2
  5. package/dist/module.d.mts +4 -0
  6. package/dist/module.json +2 -2
  7. package/dist/module.mjs +8 -4
  8. package/dist/runtime/app/index.d.ts +3 -0
  9. package/dist/runtime/app/index.js +2 -0
  10. package/dist/runtime/cache-control.d.ts +2 -0
  11. package/dist/runtime/cache-control.js +11 -0
  12. package/dist/runtime/llms-txt-utils.js +1 -1
  13. package/dist/runtime/server/db/context.d.ts +13 -0
  14. package/dist/runtime/server/db/drizzle/client.d.ts +6 -7
  15. package/dist/runtime/server/db/drizzle/client.js +13 -2
  16. package/dist/runtime/server/db/drizzle/providers/bun.d.ts +2 -2
  17. package/dist/runtime/server/db/drizzle/providers/bun.js +2 -2
  18. package/dist/runtime/server/db/drizzle/providers/d1.d.ts +2 -2
  19. package/dist/runtime/server/db/drizzle/providers/d1.js +3 -2
  20. package/dist/runtime/server/db/drizzle/providers/libsql.d.ts +2 -2
  21. package/dist/runtime/server/db/drizzle/providers/libsql.js +2 -2
  22. package/dist/runtime/server/db/drizzle/providers/neon.d.ts +2 -2
  23. package/dist/runtime/server/db/drizzle/providers/neon.js +2 -2
  24. package/dist/runtime/server/db/drizzle/providers/node-sqlite.d.ts +2 -2
  25. package/dist/runtime/server/db/drizzle/providers/node-sqlite.js +2 -2
  26. package/dist/runtime/server/db/drizzle/providers/postgres.d.ts +2 -2
  27. package/dist/runtime/server/db/drizzle/providers/postgres.js +2 -2
  28. package/dist/runtime/server/db/drizzle/queries.d.ts +27 -27
  29. package/dist/runtime/server/db/drizzle/queries.js +6 -5
  30. package/dist/runtime/server/db/drizzle/raw.d.ts +2 -6
  31. package/dist/runtime/server/db/index.d.ts +1 -1
  32. package/dist/runtime/server/db/index.js +1 -1
  33. package/dist/runtime/server/db/queries.d.ts +36 -36
  34. package/dist/runtime/server/db/queries.js +8 -9
  35. package/dist/runtime/server/db/seed.d.ts +2 -2
  36. package/dist/runtime/server/db/seed.js +4 -3
  37. package/dist/runtime/server/db/shared.d.ts +8 -0
  38. package/dist/runtime/server/db/shared.js +8 -2
  39. package/dist/runtime/server/index.d.ts +2 -0
  40. package/dist/runtime/server/index.js +17 -0
  41. package/dist/runtime/server/mcp/tools/get-page-markdown.js +1 -1
  42. package/dist/runtime/server/mcp/tools/list-pages.js +1 -1
  43. package/dist/runtime/server/mcp/tools/search-pages.js +1 -1
  44. package/dist/runtime/server/middleware/markdown.prerender.js +1 -1
  45. package/dist/runtime/server/plugins/db-lifecycle-nitro3.d.ts +2 -0
  46. package/dist/runtime/server/plugins/db-lifecycle-nitro3.js +16 -0
  47. package/dist/runtime/server/plugins/html-capture.prerender.js +6 -4
  48. package/dist/runtime/server/plugins/link-header-nitro3.d.ts +2 -0
  49. package/dist/runtime/server/plugins/link-header-nitro3.js +20 -0
  50. package/dist/runtime/server/plugins/link-header.d.ts +6 -0
  51. package/dist/runtime/server/plugins/link-header.js +7 -11
  52. package/dist/runtime/server/plugins/markdown-negotiation.js +8 -1
  53. package/dist/runtime/server/plugins/sitemap-seeder.js +3 -3
  54. package/dist/runtime/server/routes/agent-skills-artifact.d.ts +1 -1
  55. package/dist/runtime/server/routes/agent-skills-artifact.js +10 -10
  56. package/dist/runtime/server/routes/agent-skills-index.d.ts +1 -1
  57. package/dist/runtime/server/routes/agent-skills-index.js +7 -6
  58. package/dist/runtime/server/routes/ai-catalog.d.ts +2 -1
  59. package/dist/runtime/server/routes/ai-catalog.js +7 -8
  60. package/dist/runtime/server/routes/api-catalog.d.ts +3 -1
  61. package/dist/runtime/server/routes/api-catalog.js +12 -12
  62. package/dist/runtime/server/routes/llms-full.txt.get.js +1 -1
  63. package/dist/runtime/server/routes/mcp-server-card.d.ts +1 -1
  64. package/dist/runtime/server/routes/mcp-server-card.js +7 -8
  65. package/dist/runtime/server/utils/checkStale.d.ts +2 -2
  66. package/dist/runtime/server/utils/cloudflare-prerendered.d.ts +3 -0
  67. package/dist/runtime/server/utils/cloudflare-prerendered.js +23 -0
  68. package/dist/runtime/server/utils/cloudflare.d.ts +5 -5
  69. package/dist/runtime/server/utils/cloudflare.js +31 -7
  70. package/dist/runtime/server/utils/content-negotiation.d.ts +5 -3
  71. package/dist/runtime/server/utils/content-negotiation.js +8 -7
  72. package/dist/runtime/server/utils/context.d.ts +3 -3
  73. package/dist/runtime/server/utils/context.js +1 -1
  74. package/dist/runtime/server/utils/discovery-response.d.ts +2 -0
  75. package/dist/runtime/server/utils/link-header.d.ts +5 -3
  76. package/dist/runtime/server/utils/link-header.js +26 -2
  77. package/dist/runtime/server/utils/markdown-request.d.ts +4 -3
  78. package/dist/runtime/server/utils/markdown-request.js +15 -13
  79. package/dist/runtime/server/utils/negotiation-decision.d.ts +4 -0
  80. package/dist/runtime/server/utils/negotiation-decision.js +6 -5
  81. package/dist/runtime/server/utils/negotiation-response.js +47 -22
  82. package/dist/runtime/server/utils/prerender-html.d.ts +2 -1
  83. package/dist/runtime/server/utils/prerender-html.js +3 -1
  84. package/dist/runtime/types.d.ts +15 -7
  85. package/dist/shared/nuxt-ai-ready.B3hAuOLQ.mjs +29 -0
  86. package/dist/shared/{nuxt-ai-ready.CLSWou20.mjs → nuxt-ai-ready.C34F0LJo.mjs} +560 -219
  87. package/package.json +85 -20
  88. package/skills/nuxt-ai-ready/SKILL.md +26 -12
  89. package/skills/nuxt-ai-ready/references/runtime-indexing.md +7 -6
  90. package/dist/runtime/server/db/drizzle/providers/sqlite.d.ts +0 -8
  91. package/dist/runtime/server/db/drizzle/providers/sqlite.js +0 -15
  92. package/node_modules/@mdream/js/LICENSE.md +0 -9
  93. package/node_modules/@mdream/js/README.md +0 -792
  94. package/node_modules/@mdream/js/bin/mdream.mjs +0 -2
  95. package/node_modules/@mdream/js/dist/_chunks/const.mjs +0 -134
  96. package/node_modules/@mdream/js/dist/_chunks/index.d.mts +0 -9
  97. package/node_modules/@mdream/js/dist/_chunks/markdown-processor.mjs +0 -1968
  98. package/node_modules/@mdream/js/dist/_chunks/minimal.d.mts +0 -6
  99. package/node_modules/@mdream/js/dist/_chunks/parse.mjs +0 -2756
  100. package/node_modules/@mdream/js/dist/_chunks/plugins.mjs +0 -725
  101. package/node_modules/@mdream/js/dist/_chunks/resolve-plugins.mjs +0 -44
  102. package/node_modules/@mdream/js/dist/_chunks/stream.mjs +0 -37
  103. package/node_modules/@mdream/js/dist/_chunks/types.d.mts +0 -473
  104. package/node_modules/@mdream/js/dist/cli.d.mts +0 -1
  105. package/node_modules/@mdream/js/dist/cli.mjs +0 -32
  106. package/node_modules/@mdream/js/dist/core.d.mts +0 -15
  107. package/node_modules/@mdream/js/dist/core.mjs +0 -28
  108. package/node_modules/@mdream/js/dist/index.d.mts +0 -4
  109. package/node_modules/@mdream/js/dist/index.mjs +0 -58
  110. package/node_modules/@mdream/js/dist/llms-txt.d.mts +0 -86
  111. package/node_modules/@mdream/js/dist/llms-txt.mjs +0 -308
  112. package/node_modules/@mdream/js/dist/negotiate.d.mts +0 -35
  113. package/node_modules/@mdream/js/dist/negotiate.mjs +0 -121
  114. package/node_modules/@mdream/js/dist/parse.d.mts +0 -90
  115. package/node_modules/@mdream/js/dist/parse.mjs +0 -2
  116. package/node_modules/@mdream/js/dist/plugins.d.mts +0 -85
  117. package/node_modules/@mdream/js/dist/plugins.mjs +0 -2
  118. package/node_modules/@mdream/js/dist/preset/minimal.d.mts +0 -2
  119. package/node_modules/@mdream/js/dist/preset/minimal.mjs +0 -33
  120. package/node_modules/@mdream/js/dist/splitter.d.mts +0 -18
  121. package/node_modules/@mdream/js/dist/splitter.mjs +0 -194
  122. package/node_modules/@mdream/js/package.json +0 -103
  123. package/node_modules/cac/LICENSE +0 -21
  124. package/node_modules/cac/README.md +0 -492
  125. package/node_modules/cac/dist/index.d.ts +0 -196
  126. package/node_modules/cac/dist/index.js +0 -638
  127. package/node_modules/cac/package.json +0 -72
  128. package/node_modules/mdream/LICENSE.md +0 -9
  129. package/node_modules/mdream/README.md +0 -1091
  130. package/node_modules/mdream/bin/mdream.mjs +0 -46
  131. package/node_modules/mdream/dist/browser.d.mts +0 -105
  132. package/node_modules/mdream/dist/browser.mjs +0 -262
  133. package/node_modules/mdream/dist/edge.d.mts +0 -100
  134. package/node_modules/mdream/dist/edge.mjs +0 -250
  135. package/node_modules/mdream/dist/iife.js +0 -605
  136. package/node_modules/mdream/dist/index.d.mts +0 -89
  137. package/node_modules/mdream/dist/index.mjs +0 -184
  138. package/node_modules/mdream/dist/wasm.d.mts +0 -100
  139. package/node_modules/mdream/dist/wasm.mjs +0 -140
  140. package/node_modules/mdream/dist/worker.d.mts +0 -101
  141. package/node_modules/mdream/dist/worker.mjs +0 -217
  142. package/node_modules/mdream/napi/index.d.mts +0 -127
  143. package/node_modules/mdream/napi/index.d.ts +0 -127
  144. package/node_modules/mdream/napi/index.mjs +0 -725
  145. package/node_modules/mdream/napi/rust.android-arm-eabi.node +0 -0
  146. package/node_modules/mdream/napi/rust.android-arm64.node +0 -0
  147. package/node_modules/mdream/napi/rust.darwin-arm64.node +0 -0
  148. package/node_modules/mdream/napi/rust.darwin-x64.node +0 -0
  149. package/node_modules/mdream/napi/rust.freebsd-x64.node +0 -0
  150. package/node_modules/mdream/napi/rust.linux-arm-gnueabihf.node +0 -0
  151. package/node_modules/mdream/napi/rust.linux-arm64-gnu.node +0 -0
  152. package/node_modules/mdream/napi/rust.linux-arm64-musl.node +0 -0
  153. package/node_modules/mdream/napi/rust.linux-x64-gnu.node +0 -0
  154. package/node_modules/mdream/napi/rust.linux-x64-musl.node +0 -0
  155. package/node_modules/mdream/napi/rust.wasi.cjs +0 -2144
  156. package/node_modules/mdream/napi/rust.wasm32-wasi.wasm +0 -0
  157. package/node_modules/mdream/napi/rust.win32-arm64-msvc.node +0 -0
  158. package/node_modules/mdream/napi/rust.win32-x64-msvc.node +0 -0
  159. package/node_modules/mdream/node_modules/@emnapi/core/LICENSE +0 -21
  160. package/node_modules/mdream/node_modules/@emnapi/core/README.md +0 -1
  161. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.d.ts +0 -392
  162. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.full.d.ts +0 -392
  163. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.full.js +0 -8351
  164. package/node_modules/mdream/node_modules/@emnapi/core/dist/emnapi-core.js +0 -7268
  165. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/async-work.d.ts +0 -5
  166. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/async-work.js +0 -843
  167. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/index.d.ts +0 -4
  168. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/index.js +0 -3
  169. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/threadsafe-function.d.ts +0 -5
  170. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/threadsafe-function.js +0 -1010
  171. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/v8.d.ts +0 -5
  172. package/node_modules/mdream/node_modules/@emnapi/core/dist/plugins/v8.js +0 -1446
  173. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/LICENSE +0 -21
  174. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/README.md +0 -203
  175. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/dist/wasi-threads.d.ts +0 -236
  176. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/dist/wasi-threads.js +0 -1086
  177. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/package.json +0 -35
  178. package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/rollup.config.js +0 -6
  179. package/node_modules/mdream/node_modules/@emnapi/core/package.json +0 -39
  180. package/node_modules/mdream/node_modules/@emnapi/core/rollup.config.js +0 -60
  181. package/node_modules/mdream/node_modules/@emnapi/runtime/LICENSE +0 -21
  182. package/node_modules/mdream/node_modules/@emnapi/runtime/README.md +0 -1
  183. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.d.ts +0 -833
  184. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.js +0 -2306
  185. package/node_modules/mdream/node_modules/@emnapi/runtime/dist/emnapi.js.map +0 -1
  186. package/node_modules/mdream/node_modules/@emnapi/runtime/index.cjs +0 -63
  187. package/node_modules/mdream/node_modules/@emnapi/runtime/package.json +0 -39
  188. package/node_modules/mdream/node_modules/@emnapi/runtime/rollup.config.js +0 -25
  189. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/LICENSE +0 -21
  190. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/README.md +0 -203
  191. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.d.ts +0 -240
  192. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.js +0 -1118
  193. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/package.json +0 -35
  194. package/node_modules/mdream/node_modules/@emnapi/wasi-threads/rollup.config.js +0 -6
  195. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +0 -1472
  196. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +0 -1470
  197. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +0 -237
  198. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/fs.js +0 -17578
  199. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +0 -317
  200. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/package.json +0 -67
  201. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/runtime.cjs +0 -39
  202. package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/runtime.js +0 -36
  203. package/node_modules/mdream/node_modules/@tybys/wasm-util/LICENSE +0 -21
  204. package/node_modules/mdream/node_modules/@tybys/wasm-util/README.md +0 -193
  205. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/tsdoc-metadata.json +0 -11
  206. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.d.ts +0 -423
  207. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm-bundler.js +0 -2932
  208. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm.js +0 -2932
  209. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.esm.min.js +0 -1
  210. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.js +0 -2954
  211. package/node_modules/mdream/node_modules/@tybys/wasm-util/dist/wasm-util.min.js +0 -1
  212. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/asyncify.js +0 -158
  213. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/index.js +0 -13
  214. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/jspi.js +0 -46
  215. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/load.js +0 -97
  216. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/memory.js +0 -35
  217. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/error.js +0 -103
  218. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/fd.js +0 -268
  219. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/fs.js +0 -3
  220. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/index.js +0 -192
  221. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/path.js +0 -316
  222. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/preview1.js +0 -1599
  223. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/rights.js +0 -141
  224. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/types.js +0 -220
  225. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/wasi/util.js +0 -128
  226. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/cjs/webassembly.js +0 -13
  227. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/asyncify.mjs +0 -153
  228. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/index.mjs +0 -9
  229. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/jspi.mjs +0 -39
  230. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/load.mjs +0 -89
  231. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/memory.mjs +0 -28
  232. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/error.mjs +0 -97
  233. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/fd.mjs +0 -256
  234. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/fs.mjs +0 -1
  235. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/index.mjs +0 -186
  236. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/path.mjs +0 -310
  237. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/preview1.mjs +0 -1593
  238. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/rights.mjs +0 -135
  239. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/types.mjs +0 -216
  240. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/wasi/util.mjs +0 -113
  241. package/node_modules/mdream/node_modules/@tybys/wasm-util/lib/mjs/webassembly.mjs +0 -9
  242. package/node_modules/mdream/node_modules/@tybys/wasm-util/package.json +0 -58
  243. package/node_modules/mdream/node_modules/tslib/CopyrightNotice.txt +0 -15
  244. package/node_modules/mdream/node_modules/tslib/LICENSE.txt +0 -12
  245. package/node_modules/mdream/node_modules/tslib/README.md +0 -164
  246. package/node_modules/mdream/node_modules/tslib/SECURITY.md +0 -41
  247. package/node_modules/mdream/node_modules/tslib/modules/index.d.ts +0 -38
  248. package/node_modules/mdream/node_modules/tslib/modules/index.js +0 -70
  249. package/node_modules/mdream/node_modules/tslib/modules/package.json +0 -3
  250. package/node_modules/mdream/node_modules/tslib/package.json +0 -47
  251. package/node_modules/mdream/node_modules/tslib/tslib.d.ts +0 -460
  252. package/node_modules/mdream/node_modules/tslib/tslib.es6.html +0 -1
  253. package/node_modules/mdream/node_modules/tslib/tslib.es6.js +0 -402
  254. package/node_modules/mdream/node_modules/tslib/tslib.es6.mjs +0 -401
  255. package/node_modules/mdream/node_modules/tslib/tslib.html +0 -1
  256. package/node_modules/mdream/node_modules/tslib/tslib.js +0 -484
  257. package/node_modules/mdream/package.json +0 -110
  258. package/node_modules/mdream/skills/mdream/SKILL.md +0 -124
  259. package/node_modules/mdream/skills/mdream/references/runtimes.md +0 -49
  260. package/node_modules/mdream/wasm/mdream_edge.d.ts +0 -90
  261. package/node_modules/mdream/wasm/mdream_edge.js +0 -517
  262. package/node_modules/mdream/wasm/mdream_edge_bg.wasm +0 -0
  263. package/node_modules/mdream/wasm/mdream_edge_bg.wasm.d.ts +0 -20
  264. package/node_modules/mdream/wasm/package.json +0 -17
  265. package/node_modules/mdream/wasm-bundler/mdream_edge.d.ts +0 -45
  266. package/node_modules/mdream/wasm-bundler/mdream_edge.js +0 -13
  267. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.js +0 -413
  268. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.wasm +0 -0
  269. package/node_modules/mdream/wasm-bundler/mdream_edge_bg.wasm.d.ts +0 -20
  270. package/node_modules/mdream/wasm-bundler/package.json +0 -19
  271. package/node_modules/pathe/LICENSE +0 -70
  272. package/node_modules/pathe/README.md +0 -73
  273. package/node_modules/pathe/dist/index.cjs +0 -39
  274. package/node_modules/pathe/dist/index.d.cts +0 -47
  275. package/node_modules/pathe/dist/index.d.mts +0 -47
  276. package/node_modules/pathe/dist/index.d.ts +0 -47
  277. package/node_modules/pathe/dist/index.mjs +0 -19
  278. package/node_modules/pathe/dist/shared/pathe.BSlhyZSM.cjs +0 -266
  279. package/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs +0 -249
  280. package/node_modules/pathe/dist/utils.cjs +0 -82
  281. package/node_modules/pathe/dist/utils.d.cts +0 -32
  282. package/node_modules/pathe/dist/utils.d.mts +0 -32
  283. package/node_modules/pathe/dist/utils.d.ts +0 -32
  284. package/node_modules/pathe/dist/utils.mjs +0 -77
  285. package/node_modules/pathe/package.json +0 -61
  286. package/node_modules/pathe/utils.d.ts +0 -1
@@ -1,20 +1,23 @@
1
1
  import { createHash, randomBytes } from 'node:crypto';
2
2
  import { readFile, mkdir, writeFile, access } from 'node:fs/promises';
3
3
  import { createRequire } from 'node:module';
4
- import { dirname, basename, join } from 'node:path';
5
- import { hasNuxtModule, useNuxt, useLogger, addTypeTemplate, addTemplate, defineNuxtModule, createResolver, addServerImports, addServerHandler, extendRouteRules, addServerPlugin, addPlugin, addImports } from '@nuxt/kit';
6
- import defu$1, { defu } from 'defu';
7
- import { installNuxtSiteConfig, useSiteConfig, withSiteUrl } from 'nuxt-site-config/kit';
8
- import { resolveNuxtContentVersion, renderNitroTypeAugmentations, setupNitroRuntimeCompatibility } from 'nuxtseo-shared/kit';
9
- import { readPackageJSON, resolvePackageJSON } from 'pkg-types';
4
+ import { dirname, basename, join, resolve, relative } from 'node:path';
10
5
  import { fileURLToPath, pathToFileURL } from 'node:url';
6
+ import { hasNuxtModule, useNuxt, useLogger, addTypeTemplate, addTemplate, defineNuxtModule, createResolver, getLayerDirectories, tryResolveModule, directoryToURL, addServerImports, addServerHandler, extendRouteRules, getNitroVersion, addNitroPlugin, addPlugin, addImports } from '@nuxt/kit';
7
+ import defu$1, { defu } from 'defu';
8
+ import { useSiteConfig, withSiteUrl } from 'nuxt-site-config/kit';
9
+ import { resolveNuxtContentVersion, renderNitroTypeAugmentations, setupRuntimeAliases, setupNitroRuntimeCompatibility } from 'nuxtseo-shared/kit';
10
+ import { r as readPackageMetadata, a as resolvePackageMetadataPath } from './nuxt-ai-ready.B3hAuOLQ.mjs';
11
11
  import { hasMarkdownTwin, normalizePagePath, toMarkdownPath } from '../../dist/runtime/markdown-path.js';
12
+ import { toDeployedRoute } from '../../dist/runtime/route-path.js';
12
13
  import { SITEMAP_MD_ROUTE } from '../../dist/runtime/server/utils/sitemap-md.js';
13
- import { publicCacheControl } from '../../dist/runtime/cache-control.js';
14
+ import { publicCacheControl, mergeVaryHeader } from '../../dist/runtime/cache-control.js';
14
15
  import { MCP_SERVER_CARD_MEDIA_TYPE, AI_CATALOG_MEDIA_TYPE } from '../../dist/runtime/server/utils/discovery-response.js';
16
+ import { parseTOML, parseJSONC } from 'confbox';
17
+ import { createNitroRouteRuleMatcher } from 'nuxtseo-shared/server';
18
+ import { getContentNegotiationVary, resolveContentNegotiation } from '../../dist/runtime/server/utils/content-negotiation.js';
15
19
  import { isAbsolute, join as join$1 } from 'pathe';
16
20
  import { resolveI18nConfig, toRuntimeI18nConfig as toRuntimeI18nConfig$1 } from 'nuxtseo-shared/i18n';
17
- import { toDeployedRoute } from '../../dist/runtime/route-path.js';
18
21
 
19
22
  const SELECT_PAGE_DATA = "SELECT route, title, description, markdown, headings, keywords, updated_at, is_error, locale FROM ai_ready_pages";
20
23
  function createBuildPageDataVirtual(options) {
@@ -24,12 +27,9 @@ export async function readPageDataFromFilesystem() { return { pages: [], errorRo
24
27
  export async function readMarkdownLinkAvailabilityFromFilesystem() { return { runtimeMarkdownAvailable: false, paths: [] } }
25
28
  `;
26
29
  }
27
- const readRows = options.nativeNodeSqlite ? `const { DatabaseSync } = await import('node' + ':sqlite')
30
+ const readRows = `const { DatabaseSync } = await import('node' + ':sqlite')
28
31
  const db = new DatabaseSync(dbPath, { open: true })
29
32
  const rows = db.prepare(${JSON.stringify(SELECT_PAGE_DATA)}).all()
30
- db.close()` : `const Database = (await import('better-sqlite3')).default
31
- const db = new Database(dbPath, { readonly: true })
32
- const rows = db.prepare(${JSON.stringify(SELECT_PAGE_DATA)}).all()
33
33
  db.close()`;
34
34
  return `
35
35
  export async function readMarkdownLinkAvailabilityFromFilesystem() {
@@ -85,7 +85,7 @@ const COMARK_MODULE = "@harlan-zw/comark-content";
85
85
  const COMARK_MINIMUM = [0, 1, 2];
86
86
  async function comarkSatisfiesMinimum() {
87
87
  const url = useNuxt().options.rootDir;
88
- const pkg = await readPackageJSON(COMARK_MODULE, { url }).catch(() => {
88
+ const pkg = await readPackageMetadata(COMARK_MODULE, url).catch(() => {
89
89
  return null;
90
90
  });
91
91
  const parts = pkg?.version?.split(".").map((part) => Number.parseInt(part, 10));
@@ -249,15 +249,19 @@ declare module '#ai-ready-virtual/i18n-runtime.mjs' {
249
249
  }
250
250
 
251
251
  declare module '#ai-ready-virtual/db-provider.mjs' {
252
- import type { H3Event } from '#nuxtseo/h3'
252
+ import type { AiReadyDatabaseEvent } from '#ai-ready/server/db/context'
253
253
  import type { DrizzleDatabase } from '#ai-ready/server/db/drizzle/client'
254
- export function createClient(event?: H3Event): Promise<DrizzleDatabase>
254
+ export function createClient(event?: AiReadyDatabaseEvent): Promise<DrizzleDatabase>
255
255
  }
256
256
 
257
257
  declare module '#ai-ready-virtual/db-schema.mjs' {
258
258
  export * from '#ai-ready/server/db/schema/sqlite'
259
259
  }
260
260
 
261
+ declare module '#ai-ready-virtual/database-runtime.mjs' {
262
+ export * from '#ai-ready/server/db/drizzle'
263
+ }
264
+
261
265
  declare module '#ai-ready-virtual/content-lookup.mjs' {
262
266
  import type { H3Event } from '#nuxtseo/h3'
263
267
  export function lookupContentPage(event: H3Event, path: string): Promise<{
@@ -296,6 +300,7 @@ function resolveExternalSkillUrl(href, indexUrl) {
296
300
  }
297
301
 
298
302
  const AI_CATALOG_PATH = "/.well-known/ai-catalog.json";
303
+ const ARD_PATH = "/.well-known/ard.json";
299
304
  function resolveAiCatalog(input) {
300
305
  const hostname = new URL(input.siteUrl).hostname;
301
306
  const serverName = input.serverCardName.split("/").at(-1);
@@ -303,6 +308,8 @@ function resolveAiCatalog(input) {
303
308
  specVersion: "1.0",
304
309
  entries: [{
305
310
  identifier: `urn:air:${hostname}:mcp:${serverName}`,
311
+ displayName: input.serverCardTitle || input.serverCardName,
312
+ ...input.serverCardDescription ? { description: input.serverCardDescription } : {},
306
313
  type: MCP_SERVER_CARD_MEDIA_TYPE,
307
314
  url: input.serverCardUrl
308
315
  }]
@@ -512,16 +519,256 @@ function formatApiCatalogConfigError(error) {
512
519
  }
513
520
  }
514
521
 
515
- function supportsNativeNodeSqlite(version) {
516
- const [major = 0, minor = 0] = version.split(".").map(Number);
517
- if (major === 22)
518
- return minor >= 13;
519
- if (major === 23)
520
- return minor >= 4;
521
- return major > 23;
522
+ const PARSERS = {
523
+ "wrangler.json": JSON.parse,
524
+ "wrangler.jsonc": parseJSONC,
525
+ "wrangler.toml": parseTOML
526
+ };
527
+ function parseRouting(routing) {
528
+ if (routing === void 0 || typeof routing === "boolean")
529
+ return routing;
530
+ if (Array.isArray(routing) && routing.every((pattern) => typeof pattern === "string"))
531
+ return routing;
532
+ throw new Error("Cloudflare assets.run_worker_first must be a boolean or an array of path patterns.");
533
+ }
534
+ async function readCloudflareAssetRouting(rootDir) {
535
+ let directory = rootDir;
536
+ while (true) {
537
+ for (const [name, parse] of Object.entries(PARSERS)) {
538
+ const source = await readFile(join(directory, name), "utf8").catch((error) => {
539
+ if (error.code === "ENOENT")
540
+ return void 0;
541
+ throw error;
542
+ });
543
+ if (source === void 0)
544
+ continue;
545
+ const config = parse(source);
546
+ return {
547
+ root: parseRouting(config.assets?.run_worker_first),
548
+ environments: Object.values(config.env || {}).flatMap((env) => {
549
+ const routing = parseRouting(env.assets?.run_worker_first);
550
+ return routing === void 0 ? [] : [routing];
551
+ })
552
+ };
553
+ }
554
+ const parent = dirname(directory);
555
+ if (parent === directory)
556
+ return { environments: [] };
557
+ directory = parent;
558
+ }
559
+ }
560
+
561
+ const RE_MD_EXT = /\.md$/;
562
+ function isStaticMarkdownSourceRoute(route) {
563
+ if (route.includes("*") || route.includes(":"))
564
+ return false;
565
+ return hasMarkdownTwin(route.split("?")[0] || route);
566
+ }
567
+ function staticDescribedbyEntry(baseURL) {
568
+ return `<${encodeURI(toDeployedRoute("/llms.txt", baseURL))}>; rel="describedby"`;
569
+ }
570
+ function buildStaticMarkdownLinkHeader(route, baseURL, describedby) {
571
+ const htmlRoute = encodeURI(toDeployedRoute(normalizePagePath(route), baseURL));
572
+ const parts = [
573
+ `<${htmlRoute}>; rel="alternate"; type="text/html"`,
574
+ `<${htmlRoute}>; rel="canonical"`
575
+ ];
576
+ if (describedby)
577
+ parts.push(staticDescribedbyEntry(baseURL));
578
+ return parts.join(", ");
579
+ }
580
+ function pageRouteFromMarkdownTwin(fileName) {
581
+ if (!fileName?.endsWith(".md") || fileName === SITEMAP_MD_ROUTE)
582
+ return null;
583
+ const pageRoute = normalizePagePath(fileName.replace(RE_MD_EXT, ""));
584
+ if (pageRoute === "/index")
585
+ return "/";
586
+ return isStaticMarkdownSourceRoute(pageRoute) ? pageRoute : null;
587
+ }
588
+ function prerenderedMarkdownHeaderRules(prerenderedRoutes, baseURL, describedby, artifactRoutes) {
589
+ const artifacts = new Set(artifactRoutes);
590
+ const rules = /* @__PURE__ */ new Map();
591
+ for (const entry of prerenderedRoutes) {
592
+ if (entry.route !== void 0 && artifacts.has(entry.route) || entry.fileName !== void 0 && artifacts.has(entry.fileName)) {
593
+ continue;
594
+ }
595
+ const pageRoute = pageRouteFromMarkdownTwin(entry.fileName);
596
+ if (pageRoute === null)
597
+ continue;
598
+ const mdRoute = toMarkdownPath(pageRoute);
599
+ if (!rules.has(mdRoute)) {
600
+ rules.set(mdRoute, {
601
+ route: mdRoute,
602
+ headers: {
603
+ "Content-Type": "text/markdown; charset=utf-8",
604
+ "Vary": "Accept",
605
+ "Link": buildStaticMarkdownLinkHeader(pageRoute, baseURL, describedby)
606
+ }
607
+ });
608
+ }
609
+ }
610
+ return [...rules.values()];
611
+ }
612
+ const RE_EXACT_MARKDOWN_ROUTE$1 = /^\/[^*:\s]*\.md$/;
613
+ function isStaticHeaderRouteRule([, rule]) {
614
+ return Boolean(rule && "headers" in rule && rule.headers);
615
+ }
616
+ function planStaticMarkdownHeaderRules(routeRules, rules, limit) {
617
+ if (limit === null)
618
+ return { _tag: "apply", rules };
619
+ const entries = Object.entries(routeRules).filter(isStaticHeaderRouteRule);
620
+ const registeredMarkdown = entries.map(([route]) => route).filter((route) => RE_EXACT_MARKDOWN_ROUTE$1.test(route));
621
+ const other = entries.length - registeredMarkdown.length;
622
+ const markdown = /* @__PURE__ */ new Set([...registeredMarkdown, ...rules.map((rule) => rule.route)]);
623
+ const total = other + markdown.size;
624
+ if (total <= limit)
625
+ return { _tag: "apply", rules };
626
+ return { _tag: "skip", drop: registeredMarkdown, total, dropped: markdown.size };
627
+ }
628
+ function applyStaticMarkdownHeaderPlan(routeRules, plan) {
629
+ if (plan._tag === "skip") {
630
+ for (const route of plan.drop) {
631
+ const rule = routeRules[route];
632
+ if (rule)
633
+ rule.headers = void 0;
634
+ }
635
+ return;
636
+ }
637
+ for (const { route, headers } of plan.rules) {
638
+ const existing = routeRules[route];
639
+ const merged = defu({ headers: { ...headers } }, existing);
640
+ const vary = Object.entries(existing?.headers || {}).filter(([name]) => name.toLowerCase() === "vary").map(([, value]) => value).join(", ");
641
+ if (headers.Vary) {
642
+ for (const name of Object.keys(merged.headers)) {
643
+ if (name.toLowerCase() === "vary")
644
+ delete merged.headers[name];
645
+ }
646
+ merged.headers.Vary = mergeVaryHeader(vary, headers.Vary);
647
+ }
648
+ routeRules[route] = merged;
649
+ }
650
+ }
651
+
652
+ const MAX_WORKER_FIRST_PATTERNS = 100;
653
+ const RE_PATTERN_CHARACTERS = /[.+?^${}()|[\]\\]/g;
654
+ function cloudflarePrerenderedPages(routes, baseURL) {
655
+ return [...new Set(routes.filter((entry) => !entry.error && entry.fileName?.endsWith(".html") && isStaticMarkdownSourceRoute(entry.route)).map((entry) => normalizePagePath(toDeployedRoute(normalizePagePath(entry.route), baseURL))))];
656
+ }
657
+ function matchesPattern(path, pattern) {
658
+ return new RegExp(`^${pattern.replace(RE_PATTERN_CHARACTERS, "\\$&").replaceAll("*", ".*")}$`).test(path);
659
+ }
660
+ function pagePaths(pages) {
661
+ return pages.flatMap((page) => page === "/" ? ["/"] : [page, `${page}/`]);
662
+ }
663
+ function cloudflareStaticFallbackPaths(existing, pages, environments = []) {
664
+ if (existing === true || existing === false || environments.includes(true))
665
+ return [];
666
+ const patterns = [...existing || [], ...environments.flatMap((routing) => Array.isArray(routing) ? routing : [])];
667
+ return pagePaths(pages).filter((path) => !patterns.some((pattern) => matchesPattern(path, pattern.startsWith("!") ? pattern.slice(1) : pattern)));
668
+ }
669
+ function cloudflareNegotiationPatterns(existing, pages) {
670
+ if (existing === true || existing === false || pages.length === 0)
671
+ return existing;
672
+ const patterns = [...existing || []];
673
+ for (const path of cloudflareStaticFallbackPaths(existing, pages)) {
674
+ if (!patterns.includes(path))
675
+ patterns.push(path);
676
+ }
677
+ if (patterns.length > MAX_WORKER_FIRST_PATTERNS) {
678
+ throw new Error("Cloudflare Markdown negotiation exceeds 100 worker-first patterns. Configure broader assets.run_worker_first patterns, or disable aiReady.contentNegotiation.");
679
+ }
680
+ return patterns;
681
+ }
682
+
683
+ const CACHE_GUIDE = "https://nuxtseo.com/docs/ai-ready/guides/markdown#cache-safety";
684
+ function cacheFix(botNegotiation = false) {
685
+ const headers = getContentNegotiationVary(botNegotiation).split(",").map((header) => `'${header.trim().toLowerCase()}'`).join(", ");
686
+ return [
687
+ ...botNegotiation ? [
688
+ "For lower cache cost, set aiReady: { botNegotiation: false } and keep Accept-only negotiation.",
689
+ "To retain bot negotiation, include all three inputs in this route's cache key.",
690
+ "Raw User-Agent variation can create many cache entries."
691
+ ] : [],
692
+ `Add to this route rule: cache: { varies: [${headers}] }`,
693
+ "Keep existing cache options and varies entries.",
694
+ "HTTP Vary alone does not change Nitro's cache key.",
695
+ "If a CDN ignores Vary, set aiReady: { contentNegotiation: false } and use explicit .md URLs."
696
+ ].join("\n ");
697
+ }
698
+ function resolveConfigurationWarnings(input) {
699
+ const warnings = [];
700
+ const hostname = input.siteUrl && URL.canParse(input.siteUrl) ? new URL(input.siteUrl).hostname : "";
701
+ if (!hostname || hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]") {
702
+ warnings.push('Set site.url to the public production URL. Discovery catalogs and canonical Markdown links need a public origin.\n In nuxt.config.ts, set site: { url: "https://your-domain.com" }. Replace the example with your production origin.');
703
+ }
704
+ if (input.policy === "disabled") {
705
+ warnings.push(`contentNegotiation: false disables Accept and bot negotiation.
706
+ Remove aiReady.contentNegotiation from nuxt.config.ts to restore automatic negotiation.
707
+ If disabled intentionally, link explicit .md URLs and verify they resolve after deployment.
708
+ Guide: ${CACHE_GUIDE}`);
709
+ } else if (input.static) {
710
+ warnings.push(`Static output cannot run Markdown negotiation middleware.
711
+ Link the generated .md URLs, or use a server deployment for automatic negotiation.
712
+ For edge negotiation, preserve these inputs: ${getContentNegotiationVary(input.botNegotiation)}.
713
+ Guide: ${CACHE_GUIDE}`);
714
+ }
715
+ const match = createNitroRouteRuleMatcher({ nitro: { routeRules: input.routeRules } });
716
+ for (const route of Object.keys(input.routeRules).sort()) {
717
+ if (!hasMarkdownTwin(route) || route.startsWith("/.well-known/"))
718
+ continue;
719
+ const rule = match(route);
720
+ if (rule.redirect || rule.proxy)
721
+ continue;
722
+ if (input.static || input.policy === "disabled")
723
+ continue;
724
+ const automatic = resolveContentNegotiation({ policy: "auto", routeRule: rule, botNegotiation: input.botNegotiation });
725
+ const fixCache = cacheFix(input.botNegotiation);
726
+ if (automatic._tag === "enabled")
727
+ continue;
728
+ if (input.policy === "enabled") {
729
+ const fix = automatic.source === "isr" ? `ISR cannot use automatic negotiation. Set isr: false on this route, or use explicit .md URLs.${rule.cache ? `
730
+ ${fixCache}` : ""}` : fixCache;
731
+ warnings.push(`"${route}": contentNegotiation: true overrides cache protection.
732
+ Remove aiReady.contentNegotiation from nuxt.config.ts to restore automatic cache protection.
733
+ ${fix}
734
+ Guide: ${CACHE_GUIDE}`);
735
+ } else if (automatic.source === "isr") {
736
+ warnings.push(`"${route}": ISR disables automatic Markdown negotiation.
737
+ To keep ISR, use explicit .md URLs.
738
+ To use negotiation, set isr: false on this route in nuxt.config.ts.${rule.cache ? `
739
+ ${fixCache}` : ""}
740
+ Guide: ${CACHE_GUIDE}`);
741
+ } else {
742
+ warnings.push(`"${route}": response caching disables automatic Markdown negotiation.
743
+ In nuxt.config.ts:
744
+ ${fixCache}
745
+ Guide: ${CACHE_GUIDE}`);
746
+ }
747
+ }
748
+ return warnings;
522
749
  }
750
+
523
751
  const DATABASE_TYPE_NONE = "none";
524
752
  const DATABASE_DEPENDENT_OPTIONS = ["runtimeSync", "cron"];
753
+ const DATABASE_CONSUMER_LABELS = {
754
+ runtimeSync: "runtime indexing (`aiReady.runtimeSync`)",
755
+ cron: "the indexing cron (`aiReady.cron`)",
756
+ mcp: "MCP site tools (`@nuxtjs/mcp-toolkit`)",
757
+ webmcp: "WebMCP site tools (`aiReady.webmcp`)"
758
+ };
759
+ function formatMissingDrizzleMessage(input) {
760
+ const consumers = Object.keys(DATABASE_CONSUMER_LABELS).filter((consumer) => input.requested[consumer]);
761
+ const subject = consumers.length === 0 ? "The `aiReady.database` option turns on the database." : `These features need the database: ${consumers.map((consumer) => DATABASE_CONSUMER_LABELS[consumer]).join(", ")}.`;
762
+ const version = input.peerRange?.replace(/^\^/, "");
763
+ const lines = [
764
+ subject,
765
+ "The database needs `drizzle-orm`. This app does not install it.",
766
+ `Install it: npx nypm add drizzle-orm${version ? `@${version}` : ""}`
767
+ ];
768
+ if (consumers.length > 0 && consumers.every((consumer) => consumer === "mcp" || consumer === "webmcp"))
769
+ lines.push("If you do not need the site tools, set `aiReady.database: false`.");
770
+ return lines.join("\n");
771
+ }
525
772
  const DEFAULT_SQLITE_FILENAME = ".data/ai-ready/pages.db";
526
773
  function formatConflictMessage(conflicts) {
527
774
  const names = conflicts.map((option) => `\`aiReady.${option}\``).join(", ");
@@ -797,7 +1044,10 @@ function parseSupportedMcpProtocolVersions(source) {
797
1044
  async function resolveInstalledMcpProtocolVersions(input) {
798
1045
  const resolutionBases = [.../* @__PURE__ */ new Set([...input.modulesDir, input.rootDir])];
799
1046
  const sdkResolutionAttempts = resolutionBases.map(
800
- (base) => resolvePackageJSON("@nuxtjs/mcp-toolkit", { from: base }).then((toolkitPackagePath) => createRequire(toolkitPackagePath).resolve("@modelcontextprotocol/sdk/types.js"))
1047
+ (base) => Promise.resolve().then(() => {
1048
+ const toolkitPackagePath = resolvePackageMetadataPath("@nuxtjs/mcp-toolkit", base, input.modulesDir.includes(base) ? { searchDirectory: base } : void 0);
1049
+ return createRequire(toolkitPackagePath).resolve("@modelcontextprotocol/sdk/types.js");
1050
+ })
801
1051
  );
802
1052
  return Promise.allSettled(sdkResolutionAttempts).then((results) => {
803
1053
  const resolved = results.find((result) => result.status === "fulfilled");
@@ -852,7 +1102,7 @@ function createMcpServerCardEtag(card) {
852
1102
  function escapeRegExp(value) {
853
1103
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
854
1104
  }
855
- function ensureStaticHeader(contents, route, name, value) {
1105
+ function ensureStaticHeader(contents, route, name, value, mode = "default") {
856
1106
  const eol = contents.includes("\r\n") ? "\r\n" : "\n";
857
1107
  const routePattern = new RegExp(`^${escapeRegExp(route)}[\\t ]*\\r?$`, "gm");
858
1108
  const routeMatches = [...contents.matchAll(routePattern)];
@@ -874,13 +1124,60 @@ function ensureStaticHeader(contents, route, name, value) {
874
1124
  "im"
875
1125
  );
876
1126
  if (existingHeaderPattern.test(block)) {
1127
+ if (mode === "append") {
1128
+ const removalPattern = new RegExp(`^[\\t ]+![\\t ]*${escapedName}[\\t ]*\\r?$`, "im");
1129
+ if (removalPattern.test(block))
1130
+ return contents;
1131
+ const valuePattern = new RegExp(`^([\\t ]+${escapedName}[\\t ]*:[\\t ]*)([^\\r\\n]*)(\\r?$)`, "im");
1132
+ const match = block.match(valuePattern);
1133
+ if (match) {
1134
+ const merged = block.replace(valuePattern, (_line, prefix2, current, suffix) => {
1135
+ const appended = name.toLowerCase() === "link" ? current.includes(value) ? current : [current, value].filter(Boolean).join(", ") : mergeVaryHeader(current, value);
1136
+ return `${prefix2}${appended}${suffix}`;
1137
+ });
1138
+ return `${contents.slice(0, blockStart)}${merged}${contents.slice(blockEnd)}`;
1139
+ }
1140
+ }
877
1141
  return contents;
878
1142
  }
879
1143
  const prefix = blockStart === routeLineEnd ? eol : "";
880
1144
  return `${contents.slice(0, blockStart)}${prefix} ${name}: ${value}${eol}${contents.slice(blockStart)}`;
881
1145
  }
1146
+ function mergeStaticDiscoveryHeaders(contents, baseURL, entries) {
1147
+ if (entries.length === 0)
1148
+ return contents;
1149
+ const route = toDeployedRoute("/*", baseURL);
1150
+ const blocks = splitHeaderBlocks(contents);
1151
+ const matching = blocks.filter((block) => block.route === route);
1152
+ let merged = matching[0]?.text || "";
1153
+ for (const block of matching.slice(1)) {
1154
+ for (const line of block.text.split(/(?<=\n)/).slice(1)) {
1155
+ const header = line.match(/^[\t ]+([^:\s]+):[\t ]*([^\r\n]*)/);
1156
+ if (header?.[1]?.toLowerCase() === "link") {
1157
+ merged = ensureStaticHeader(merged, route, header[1], header[2], "append");
1158
+ } else if (header) {
1159
+ const existing = new RegExp(`^[\\t ]+${escapeRegExp(header[1])}[\\t ]*:[^\\r\\n]*(?:\\r?\\n|$)`, "gim");
1160
+ merged = ensureStaticHeader(merged.replace(existing, ""), route, header[1], header[2]);
1161
+ } else {
1162
+ merged += line;
1163
+ }
1164
+ }
1165
+ }
1166
+ if (matching.length > 1) {
1167
+ let inserted = false;
1168
+ contents = blocks.map((block) => {
1169
+ if (block.route !== route)
1170
+ return block.text;
1171
+ if (inserted)
1172
+ return "";
1173
+ inserted = true;
1174
+ return merged;
1175
+ }).join("");
1176
+ }
1177
+ return entries.reduce((headers, entry) => ensureStaticHeader(headers, route, "Link", entry, "append"), contents);
1178
+ }
882
1179
  const CLOUDFLARE_STATIC_HEADER_RULE_LIMIT = 100;
883
- const RE_EXACT_MARKDOWN_ROUTE$1 = /^\/[^*\s]*\.md[\t ]*\r?$/;
1180
+ const RE_EXACT_MARKDOWN_ROUTE = /^\/[^*\s]*\.md[\t ]*\r?$/;
884
1181
  function splitHeaderBlocks(contents) {
885
1182
  const blocks = [];
886
1183
  let current = { route: null, text: "" };
@@ -900,7 +1197,7 @@ function enforceStaticHeaderBudget(contents, limit) {
900
1197
  const ruleCount = blocks.filter((block) => block.route !== null).length;
901
1198
  if (ruleCount <= limit)
902
1199
  return { contents, total: ruleCount, dropped: 0 };
903
- const kept = blocks.filter((block) => block.route === null || !RE_EXACT_MARKDOWN_ROUTE$1.test(block.route));
1200
+ const kept = blocks.filter((block) => block.route === null || !RE_EXACT_MARKDOWN_ROUTE.test(block.route));
904
1201
  return {
905
1202
  contents: kept.map((block) => block.text).join(""),
906
1203
  total: kept.filter((block) => block.route !== null).length,
@@ -908,85 +1205,6 @@ function enforceStaticHeaderBudget(contents, limit) {
908
1205
  };
909
1206
  }
910
1207
 
911
- const RE_MD_EXT = /\.md$/;
912
- function isStaticMarkdownSourceRoute(route) {
913
- if (route.includes("*") || route.includes(":"))
914
- return false;
915
- return hasMarkdownTwin(route.split("?")[0] || route);
916
- }
917
- function staticDescribedbyEntry(baseURL) {
918
- return `<${encodeURI(toDeployedRoute("/llms.txt", baseURL))}>; rel="describedby"`;
919
- }
920
- function buildStaticMarkdownLinkHeader(route, baseURL, describedby) {
921
- const htmlRoute = encodeURI(toDeployedRoute(normalizePagePath(route), baseURL));
922
- const parts = [
923
- `<${htmlRoute}>; rel="alternate"; type="text/html"`,
924
- `<${htmlRoute}>; rel="canonical"`
925
- ];
926
- if (describedby)
927
- parts.push(staticDescribedbyEntry(baseURL));
928
- return parts.join(", ");
929
- }
930
- function pageRouteFromMarkdownTwin(fileName) {
931
- if (!fileName?.endsWith(".md") || fileName === SITEMAP_MD_ROUTE)
932
- return null;
933
- const pageRoute = normalizePagePath(fileName.replace(RE_MD_EXT, ""));
934
- if (pageRoute === "/index")
935
- return "/";
936
- return isStaticMarkdownSourceRoute(pageRoute) ? pageRoute : null;
937
- }
938
- function prerenderedMarkdownHeaderRules(prerenderedRoutes, baseURL, describedby, artifactRoutes) {
939
- const artifacts = new Set(artifactRoutes);
940
- const rules = /* @__PURE__ */ new Map();
941
- for (const entry of prerenderedRoutes) {
942
- if (entry.route !== void 0 && artifacts.has(entry.route) || entry.fileName !== void 0 && artifacts.has(entry.fileName)) {
943
- continue;
944
- }
945
- const pageRoute = pageRouteFromMarkdownTwin(entry.fileName);
946
- if (pageRoute === null)
947
- continue;
948
- const mdRoute = toMarkdownPath(pageRoute);
949
- if (!rules.has(mdRoute)) {
950
- rules.set(mdRoute, {
951
- route: mdRoute,
952
- headers: {
953
- "Content-Type": "text/markdown; charset=utf-8",
954
- "Link": buildStaticMarkdownLinkHeader(pageRoute, baseURL, describedby)
955
- }
956
- });
957
- }
958
- }
959
- return [...rules.values()];
960
- }
961
- const RE_EXACT_MARKDOWN_ROUTE = /^\/[^*:\s]*\.md$/;
962
- function isStaticHeaderRouteRule([, rule]) {
963
- return Boolean(rule && "headers" in rule && rule.headers);
964
- }
965
- function planStaticMarkdownHeaderRules(routeRules, rules, limit) {
966
- if (limit === null)
967
- return { _tag: "apply", rules };
968
- const entries = Object.entries(routeRules).filter(isStaticHeaderRouteRule);
969
- const registeredMarkdown = entries.map(([route]) => route).filter((route) => RE_EXACT_MARKDOWN_ROUTE.test(route));
970
- const other = entries.length - registeredMarkdown.length;
971
- const markdown = /* @__PURE__ */ new Set([...registeredMarkdown, ...rules.map((rule) => rule.route)]);
972
- const total = other + markdown.size;
973
- if (total <= limit)
974
- return { _tag: "apply", rules };
975
- return { _tag: "skip", drop: registeredMarkdown, total, dropped: markdown.size };
976
- }
977
- function applyStaticMarkdownHeaderPlan(routeRules, plan) {
978
- if (plan._tag === "skip") {
979
- for (const route of plan.drop) {
980
- const rule = routeRules[route];
981
- if (rule)
982
- rule.headers = void 0;
983
- }
984
- return;
985
- }
986
- for (const { route, headers } of plan.rules)
987
- routeRules[route] = defu({ headers }, routeRules[route]);
988
- }
989
-
990
1208
  const DEFAULT_MAX_OUTPUT_CHARS = 1500;
991
1209
  const DEFAULT_LIST_LIMIT = 20;
992
1210
  const DEFAULT_SEARCH_LIMIT = 10;
@@ -1104,22 +1322,24 @@ const module$1 = defineNuxtModule({
1104
1322
  meta: {
1105
1323
  name: "nuxt-ai-ready",
1106
1324
  compatibility: {
1107
- nuxt: ">=4.0.0"
1325
+ nuxt: "^4.6.0 || ^5.0.0-0"
1108
1326
  },
1109
1327
  configKey: "aiReady"
1110
1328
  },
1111
1329
  moduleDependencies: {
1112
- "@nuxtjs/robots": {
1113
- version: ">=6.0.0"
1330
+ [fileURLToPath(import.meta.resolve("@nuxtjs/robots"))]: {
1331
+ version: ">=7.0.0"
1114
1332
  },
1115
- "@nuxtjs/sitemap": {
1116
- version: ">=8.3.0"
1333
+ [fileURLToPath(import.meta.resolve("@nuxtjs/sitemap"))]: {
1334
+ version: ">=9.0.0"
1117
1335
  },
1118
- "nuxt-site-config": {
1119
- version: ">=3.2"
1336
+ // Keep package-relative resolution until the minimum Nuxt version includes this fix:
1337
+ // https://github.com/nuxt/nuxt/pull/36542
1338
+ [fileURLToPath(import.meta.resolve("nuxt-site-config"))]: {
1339
+ version: ">=5.0.0"
1120
1340
  },
1121
- "nuxtseo-shared": {
1122
- version: ">=5.3.11"
1341
+ [fileURLToPath(import.meta.resolve("nuxtseo-shared"))]: {
1342
+ version: ">=6.0.0"
1123
1343
  },
1124
1344
  "@nuxtjs/mcp-toolkit": {
1125
1345
  version: ">=0.18.0",
@@ -1148,13 +1368,14 @@ const module$1 = defineNuxtModule({
1148
1368
  const resolveFromModule = createRequire(moduleEntryUrl);
1149
1369
  const nuxtSeoSharedI18nRuntimePath = resolveFromModule.resolve("nuxtseo-shared/i18n-runtime");
1150
1370
  const nuxtSeoSharedUtilsPath = resolveFromModule.resolve("nuxtseo-shared/utils");
1151
- const { resolve } = createResolver(moduleEntryUrl);
1152
- const { version } = await readPackageJSON(resolve("../package.json"));
1371
+ const { resolve: resolve$1 } = createResolver(moduleEntryUrl);
1372
+ const { version, peerDependencies } = await readPackageMetadata(resolve$1("../package.json"));
1153
1373
  logger.level = config.debug || nuxt.options.debug ? 4 : 3;
1154
1374
  if (config.enabled === false) {
1155
1375
  logger.debug("Module is disabled, skipping setup.");
1156
1376
  return;
1157
1377
  }
1378
+ setupRuntimeAliases({ namespace: "#ai-ready", app: resolve$1("./runtime/app"), server: resolve$1("./runtime/server") }, nuxt);
1158
1379
  const agentSkillsConfig = config.agentSkills === false ? false : config.agentSkills ?? {};
1159
1380
  const agentSkillsError = (issues) => {
1160
1381
  const details = issues.map((issue) => `${issue.index === void 0 ? "agentSkills" : `agentSkills.skills[${issue.index}]`}.${issue.field}: ${issue.message}`).join("\n");
@@ -1166,7 +1387,8 @@ ${details}`);
1166
1387
  const { applyRootAlias, prepareAgentSkills, resolveAgentSkillsConfig } = await import('../chunks/agent-skills.mjs');
1167
1388
  const prepared = await prepareAgentSkills(agentSkillsConfig, {
1168
1389
  rootDir: nuxt.options.rootDir,
1169
- scanDirs: nuxt.options._layers.map((layer) => layer.config.rootDir ?? layer.cwd)
1390
+ scanDirs: getLayerDirectories(nuxt).map((layer) => layer.root),
1391
+ publicDirs: getLayerDirectories(nuxt).map((layer) => layer.public)
1170
1392
  });
1171
1393
  if (prepared._tag === "Invalid")
1172
1394
  throw agentSkillsError(prepared.issues);
@@ -1178,7 +1400,7 @@ ${details}`);
1178
1400
  agentSkillsResult = await resolveAgentSkillsConfig(
1179
1401
  { ...agentSkillsConfig, skills: rooted.skills },
1180
1402
  nuxt.options.rootDir,
1181
- { sitemapMd: config.sitemapMd !== false }
1403
+ { sitemapMd: config.sitemapMd !== false, publicDirs: getLayerDirectories(nuxt).map((layer) => layer.public) }
1182
1404
  );
1183
1405
  if (agentSkillsResult._tag === "Invalid")
1184
1406
  throw agentSkillsError(agentSkillsResult.issues);
@@ -1205,18 +1427,19 @@ ${details}`);
1205
1427
  });
1206
1428
  const mcpNeedsDatabase = mcpToolkitState._tag === "Enabled" && (config.mcp?.resources !== false || config.mcp?.tools !== false && Object.values(requestedSiteTools.config).some((tool) => tool.mcp.enabled));
1207
1429
  const webmcpNeedsDatabase = !!config.webmcp && (config.webmcp === true || config.webmcp.tools !== false) && Object.values(requestedSiteTools.config).some((tool) => tool.webmcp.enabled);
1430
+ const databaseRequested = {
1431
+ runtimeSync: !!config.runtimeSync,
1432
+ cron: !!config.cron,
1433
+ mcp: mcpNeedsDatabase,
1434
+ webmcp: webmcpNeedsDatabase
1435
+ };
1208
1436
  const databaseResolution = resolveDatabaseConfig({
1209
1437
  database: config.database,
1210
1438
  rootDir: nuxt.options.rootDir,
1211
1439
  preset: String(nuxt.options.nitro.preset || ""),
1212
1440
  // Vercel Postgres sets POSTGRES_URL.
1213
1441
  hasPostgresUrl: !!(process.env.POSTGRES_URL || process.env.DATABASE_URL || (config.database || void 0)?.url),
1214
- requested: {
1215
- runtimeSync: !!config.runtimeSync,
1216
- cron: !!config.cron,
1217
- mcp: mcpNeedsDatabase,
1218
- webmcp: webmcpNeedsDatabase
1219
- }
1442
+ requested: databaseRequested
1220
1443
  });
1221
1444
  if (databaseResolution._tag === "Invalid")
1222
1445
  throw new Error(`[nuxt-ai-ready] ${databaseResolution.message}`);
@@ -1224,6 +1447,11 @@ ${details}`);
1224
1447
  logger[log.level](log.message);
1225
1448
  const database = databaseResolution.database;
1226
1449
  const databaseEnabled = database._tag === "Enabled";
1450
+ if (databaseEnabled) {
1451
+ const drizzle = await tryResolveModule("drizzle-orm", directoryToURL(nuxt.options.rootDir));
1452
+ if (!drizzle)
1453
+ throw new Error(`[nuxt-ai-ready] ${formatMissingDrizzleMessage({ requested: databaseRequested, peerRange: peerDependencies["drizzle-orm"] })}`);
1454
+ }
1227
1455
  if (!databaseEnabled)
1228
1456
  logger.debug("Database disabled. Page storage, runtime indexing and site tools are off.");
1229
1457
  const siteToolsResult = databaseEnabled ? requestedSiteTools : resolveSiteToolsConfig(config.tools, { database });
@@ -1231,7 +1459,6 @@ ${details}`);
1231
1459
  logger.warn(warning);
1232
1460
  const siteToolsConfig = siteToolsResult.config;
1233
1461
  const hasMcpSiteTools = Object.values(siteToolsConfig).some((tool) => tool.mcp.enabled);
1234
- await installNuxtSiteConfig();
1235
1462
  const nitroCompatibility = setupNitroRuntimeCompatibility(nuxt);
1236
1463
  const siteConfig = useSiteConfig();
1237
1464
  const apiCatalogResult = resolveApiCatalogConfig(config.apiCatalog, {
@@ -1260,6 +1487,10 @@ ${details}`);
1260
1487
  nuxt.options.mcp = configuredMcpOptions;
1261
1488
  nuxt.options.mcp.name = mcpServerCardName;
1262
1489
  }
1490
+ if (nuxt.options.mcp !== false && config.mcp?.tools !== false && hasMcpSiteTools) {
1491
+ nuxt.options.mcp = configuredMcpOptions;
1492
+ nuxt.options.mcp.instructions ??= "Use this server when you need information from this site's indexed pages. Read the available tool descriptions before choosing a tool.";
1493
+ }
1263
1494
  const i18nConfig = await detectI18n({ autoI18n: config.autoI18n });
1264
1495
  if (i18nConfig) {
1265
1496
  logger.info(`i18n detected: ${i18nConfig.locales.length} locales (default: ${i18nConfig.defaultLocale}, strategy: ${i18nConfig.strategy})`);
@@ -1289,7 +1520,7 @@ ${details}`);
1289
1520
  });
1290
1521
  }
1291
1522
  const ftsTokenizer = i18nConfig && hasCjkLocale(i18nConfig) ? "trigram" : "unicode61 remove_diacritics 2";
1292
- nuxt.options.alias["#ai-ready"] = resolve("./runtime");
1523
+ nuxt.options.alias["#ai-ready"] = resolve$1("./runtime");
1293
1524
  addServerImports([
1294
1525
  "countPages",
1295
1526
  "indexPage",
@@ -1299,26 +1530,11 @@ ${details}`);
1299
1530
  "streamPages"
1300
1531
  ].map((name) => ({
1301
1532
  name,
1302
- from: resolve("./runtime")
1533
+ from: resolve$1("./runtime")
1303
1534
  })));
1304
- let betterSqlite3Availability;
1305
- const hasBetterSqlite3 = () => {
1306
- betterSqlite3Availability ||= resolvePackageJSON("better-sqlite3", { from: nuxt.options.rootDir }).then(
1307
- () => true,
1308
- // Missing is expected when no requested feature uses SQLite.
1309
- () => false
1310
- );
1311
- return betterSqlite3Availability;
1312
- };
1313
- const nativeNodeSqlite = supportsNativeNodeSqlite(process.versions.node || "");
1314
- if (database._tag === "Enabled" && database.type === "sqlite" && !nativeNodeSqlite && !await hasBetterSqlite3()) {
1315
- throw new Error(
1316
- `[nuxt-ai-ready] SQLite needs "better-sqlite3" on Node ${process.versions.node}, but it isn't installed. Add it to your app: \`npm i better-sqlite3\` (or \`pnpm add\` / \`yarn add\`). Node 22.13 and later use built-in \`node:sqlite\`. For edge deployments, configure D1, Neon, LibSQL, or Bun instead.`
1317
- );
1318
- }
1319
1535
  let mcpAvailable = mcpToolkitState._tag === "Enabled";
1320
1536
  nuxt.hook("mcp:definitions:paths", (paths) => {
1321
- const mcpRuntimeDir = resolve("./runtime/server/mcp");
1537
+ const mcpRuntimeDir = resolve$1("./runtime/server/mcp");
1322
1538
  const mcpConfig = config.mcp || {};
1323
1539
  if (mcpConfig.tools !== false && hasMcpSiteTools)
1324
1540
  (paths.tools ||= []).push(`${mcpRuntimeDir}/tools`);
@@ -1396,18 +1612,13 @@ ${details}`);
1396
1612
  const hasPrerenderedRoutes = !!(nuxt.options.nitro.prerender?.routes?.length || nuxt.options.nitro.prerender?.crawlLinks);
1397
1613
  const preparing = nuxt.options._prepare === true;
1398
1614
  const prerenderEnabled = !preparing && !!(isStatic || hasPrerenderedRoutes);
1399
- if (prerenderEnabled && !nativeNodeSqlite && !await hasBetterSqlite3()) {
1400
- throw new Error(
1401
- `[nuxt-ai-ready] Build time page indexing needs "better-sqlite3" on Node ${process.versions.node}. Add it to your app: \`npm i better-sqlite3\` (or \`pnpm add\` / \`yarn add\`). Node 22.13 and later need no extra package.`
1402
- );
1403
- }
1404
1615
  const isSPA = nuxt.options.ssr === false;
1405
1616
  let apiCatalogRegistered = false;
1406
1617
  const registerApiCatalog = (catalog) => {
1407
1618
  if (apiCatalogRegistered)
1408
1619
  return;
1409
1620
  apiCatalogRegistered = true;
1410
- addServerHandler({ route: API_CATALOG_PATH, handler: resolve("./runtime/server/routes/api-catalog"), lazy: true });
1621
+ addServerHandler({ route: API_CATALOG_PATH, handler: resolve$1("./runtime/server/routes/api-catalog"), lazy: true });
1411
1622
  const apiCatalogLink = `<${catalog.href}>; rel="api-catalog"`;
1412
1623
  extendRouteRules("/**", {
1413
1624
  headers: { Link: apiCatalogLink }
@@ -1466,7 +1677,7 @@ ${details}`);
1466
1677
  const mcpLink = {
1467
1678
  title: "MCP",
1468
1679
  href: withSiteUrl(finalMcpToolkitState.route, { withBase: true }),
1469
- description: "Model Context Protocol server endpoint for AI agent integration."
1680
+ description: config.mcp?.tools !== false && hasMcpSiteTools ? "Use this MCP endpoint when you need information from this site's indexed pages." : "Model Context Protocol server endpoint for AI agent integration."
1470
1681
  };
1471
1682
  const firstSection = mergedLlmsTxt.sections?.[0];
1472
1683
  if (firstSection) {
@@ -1550,7 +1761,7 @@ ${details}`);
1550
1761
  cacheMaxAge: mcpServerCardResult.config.cacheMaxAge,
1551
1762
  etag
1552
1763
  };
1553
- const handler = resolve("./runtime/server/routes/mcp-server-card");
1764
+ const handler = resolve$1("./runtime/server/routes/mcp-server-card");
1554
1765
  addServerHandler({ route: mcpServerCardRoute, method: "get", handler, lazy: true });
1555
1766
  addServerHandler({ route: mcpServerCardRoute, method: "head", handler, lazy: true });
1556
1767
  addServerHandler({ route: mcpServerCardRoute, method: "options", handler, lazy: true });
@@ -1570,6 +1781,8 @@ ${details}`);
1570
1781
  const document = resolveAiCatalog({
1571
1782
  siteUrl: siteConfig.url,
1572
1783
  serverCardName: card.name,
1784
+ serverCardTitle: card.title,
1785
+ serverCardDescription: card.description,
1573
1786
  serverCardUrl: withSiteUrl(mcpServerCardRoute, { withBase: true })
1574
1787
  });
1575
1788
  const aiCatalogEtag = createAiCatalogEtag(document);
@@ -1579,22 +1792,24 @@ ${details}`);
1579
1792
  document,
1580
1793
  etag: aiCatalogEtag
1581
1794
  };
1582
- const aiCatalogHandler = resolve("./runtime/server/routes/ai-catalog");
1583
- addServerHandler({ route: AI_CATALOG_PATH, method: "get", handler: aiCatalogHandler, lazy: true });
1584
- addServerHandler({ route: AI_CATALOG_PATH, method: "head", handler: aiCatalogHandler, lazy: true });
1585
- addServerHandler({ route: AI_CATALOG_PATH, method: "options", handler: aiCatalogHandler, lazy: true });
1586
- extendRouteRules(AI_CATALOG_PATH, {
1587
- sitemap: false,
1588
- headers: {
1589
- "Access-Control-Allow-Headers": "Content-Type, If-None-Match",
1590
- "Access-Control-Allow-Methods": "GET, HEAD",
1591
- "Access-Control-Allow-Origin": "*",
1592
- "Access-Control-Expose-Headers": "ETag",
1593
- "Cache-Control": `public, max-age=${aiCatalogCacheMaxAge}`,
1594
- "Content-Type": AI_CATALOG_MEDIA_TYPE,
1595
- "ETag": aiCatalogEtag
1596
- }
1597
- });
1795
+ const aiCatalogHandler = resolve$1("./runtime/server/routes/ai-catalog");
1796
+ for (const route of [ARD_PATH, AI_CATALOG_PATH]) {
1797
+ addServerHandler({ route, method: "get", handler: aiCatalogHandler, lazy: true });
1798
+ addServerHandler({ route, method: "head", handler: aiCatalogHandler, lazy: true });
1799
+ addServerHandler({ route, method: "options", handler: aiCatalogHandler, lazy: true });
1800
+ extendRouteRules(route, {
1801
+ sitemap: false,
1802
+ headers: {
1803
+ "Access-Control-Allow-Headers": "Content-Type, If-None-Match",
1804
+ "Access-Control-Allow-Methods": "GET, HEAD",
1805
+ "Access-Control-Allow-Origin": "*",
1806
+ "Access-Control-Expose-Headers": "ETag",
1807
+ "Cache-Control": `public, max-age=${aiCatalogCacheMaxAge}`,
1808
+ "Content-Type": AI_CATALOG_MEDIA_TYPE,
1809
+ "ETag": aiCatalogEtag
1810
+ }
1811
+ });
1812
+ }
1598
1813
  }
1599
1814
  });
1600
1815
  const sitemapConfig = nuxt.options.sitemap;
@@ -1614,6 +1829,15 @@ ${details}`);
1614
1829
  await writeFile(join(cacheDir, "secret"), runtimeSyncSecret);
1615
1830
  }
1616
1831
  nuxt.hooks.hook("nitro:config", (nitroConfig) => {
1832
+ if (getNitroVersion(nuxt) === 3) {
1833
+ const nativeConfig = nitroConfig;
1834
+ if (nativeConfig.noExternals !== true)
1835
+ nativeConfig.noExternals = [...nativeConfig.noExternals || [], "nuxt-ai-ready"];
1836
+ } else {
1837
+ const externals = nitroConfig.externals ||= {};
1838
+ externals.inline ||= [];
1839
+ externals.inline.push(resolve$1("./runtime"));
1840
+ }
1617
1841
  nitroConfig.experimental = nitroConfig.experimental || {};
1618
1842
  nitroConfig.experimental.asyncContext = true;
1619
1843
  const preset = String(nitroConfig.preset || "");
@@ -1622,20 +1846,11 @@ ${details}`);
1622
1846
  nitroConfig.experimental.wasm = true;
1623
1847
  if (nitroCompatibility._tag === "nitro-v3") {
1624
1848
  const nitro3Config = nitroConfig;
1625
- const noExternals = Array.isArray(nitro3Config.noExternals) ? nitro3Config.noExternals : [];
1626
- noExternals.push("sitemapd");
1627
- nitro3Config.noExternals = noExternals;
1849
+ if (nitro3Config.noExternals !== true)
1850
+ nitro3Config.noExternals = [...nitro3Config.noExternals || [], "sitemapd"];
1628
1851
  if (!isEdgePreset) {
1629
1852
  nitro3Config.traceDeps ||= [];
1630
1853
  nitro3Config.traceDeps.push("mdream*");
1631
- nitro3Config.rolldownConfig ||= {};
1632
- const external = nitro3Config.rolldownConfig.external;
1633
- if (Array.isArray(external))
1634
- external.push("mdream");
1635
- else if (typeof external === "string" || external instanceof RegExp)
1636
- nitro3Config.rolldownConfig.external = [external, "mdream"];
1637
- else if (!external)
1638
- nitro3Config.rolldownConfig.external = ["mdream"];
1639
1854
  }
1640
1855
  } else {
1641
1856
  const externals = nitroConfig.externals ||= {};
@@ -1666,7 +1881,7 @@ ${details}`);
1666
1881
  nitroConfig.experimental.tasks = true;
1667
1882
  nitroConfig.tasks = nitroConfig.tasks || {};
1668
1883
  nitroConfig.tasks["ai-ready:cron"] = {
1669
- handler: resolve("./runtime/server/tasks/ai-ready-cron")
1884
+ handler: resolve$1("./runtime/server/tasks/ai-ready-cron")
1670
1885
  };
1671
1886
  nitroConfig.scheduledTasks = nitroConfig.scheduledTasks || {};
1672
1887
  nitroConfig.scheduledTasks[cronSchedule] = nitroConfig.scheduledTasks[cronSchedule] || [];
@@ -1701,7 +1916,6 @@ export const localAgentSkillArtifacts = ${JSON.stringify(agentSkillsResult.local
1701
1916
  nitroConfig.virtual["#ai-ready-virtual/read-page-data.mjs"] = createBuildPageDataVirtual({
1702
1917
  buildDbPath,
1703
1918
  markdownLinkAvailabilityPath,
1704
- nativeNodeSqlite,
1705
1919
  dev: nuxt.options.dev
1706
1920
  });
1707
1921
  nitroConfig.virtual["#ai-ready-virtual/page-data.mjs"] = `export const pages = []
@@ -1711,7 +1925,7 @@ import { createModuleLogger } from ${JSON.stringify(nuxtSeoSharedUtilsPath)}
1711
1925
  export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1712
1926
  `;
1713
1927
  const providerMap = {
1714
- sqlite: nativeNodeSqlite ? "#ai-ready/server/db/drizzle/providers/node-sqlite" : "#ai-ready/server/db/drizzle/providers/sqlite",
1928
+ sqlite: "#ai-ready/server/db/drizzle/providers/node-sqlite",
1715
1929
  bun: "#ai-ready/server/db/drizzle/providers/bun",
1716
1930
  d1: "#ai-ready/server/db/drizzle/providers/d1",
1717
1931
  libsql: "#ai-ready/server/db/drizzle/providers/libsql",
@@ -1721,8 +1935,52 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1721
1935
  nitroConfig.virtual["#ai-ready-virtual/db-provider.mjs"] = database._tag === "Enabled" ? `export { createClient } from '${providerMap[database.type] || providerMap.sqlite}'` : `export function createClient() {
1722
1936
  throw new Error('[nuxt-ai-ready] The database is disabled. Set \`aiReady.database\` to store pages at runtime.')
1723
1937
  }`;
1938
+ const databaseRuntime = "#ai-ready-virtual/database-runtime.mjs";
1939
+ if (database._tag === "Disabled") {
1940
+ const databaseExports = [
1941
+ "useDrizzle",
1942
+ "useRawDb",
1943
+ "completeCronRun",
1944
+ "countPages",
1945
+ "deleteInfoValue",
1946
+ "getAllPages",
1947
+ "getContentHashes",
1948
+ "getInfoValue",
1949
+ "getNextSitemapToCrawl",
1950
+ "getPageByRoute",
1951
+ "getPageLastmods",
1952
+ "getPendingPages",
1953
+ "getRecentCronRuns",
1954
+ "getSitemapStatus",
1955
+ "initSchema",
1956
+ "markPageIndexed",
1957
+ "markRoutesPending",
1958
+ "markSitemapCrawled",
1959
+ "markSitemapCrawlPartial",
1960
+ "markSitemapError",
1961
+ "markSitemapSeeded",
1962
+ "resetSitemapErrors",
1963
+ "searchPages",
1964
+ "seedRoutes",
1965
+ "setInfoValue",
1966
+ "startCronRun",
1967
+ "syncSitemaps",
1968
+ "upsertPage"
1969
+ ];
1970
+ nitroConfig.virtual[databaseRuntime] = `
1971
+ async function unavailable() {
1972
+ throw new Error('[nuxt-ai-ready] The database is disabled. Set \`aiReady.database\` to store pages at runtime.')
1973
+ }
1974
+ export { ${databaseExports.map((name) => `unavailable as ${name}`).join(", ")} }
1975
+ export async function closeDrizzle() {}
1976
+ export async function finishDrizzleResponse() {}
1977
+ export function trackDrizzleWork(event, work) { return work }
1978
+ `;
1979
+ } else {
1980
+ nitroConfig.virtual[databaseRuntime] = `export * from '#ai-ready/server/db/drizzle'`;
1981
+ }
1724
1982
  const schemaPath = database._tag === "Enabled" && (database.type === "neon" || database.type === "postgres") ? "#ai-ready/server/db/schema/postgres" : "#ai-ready/server/db/schema/sqlite";
1725
- nitroConfig.virtual["#ai-ready-virtual/db-schema.mjs"] = `export * from '${schemaPath}'`;
1983
+ nitroConfig.virtual["#ai-ready-virtual/db-schema.mjs"] = database._tag === "Enabled" ? `export * from '${schemaPath}'` : "export {}";
1726
1984
  nitroConfig.virtual["#ai-ready-virtual/devtools-meta.mjs"] = `export const devtoolsMeta = ${JSON.stringify({
1727
1985
  contentSignal: config.contentSignal || false,
1728
1986
  mcp: { enabled: mcpAvailable, tools: mcpAvailable && config.mcp?.tools !== false && hasMcpSiteTools, resources: mcpAvailable && config.mcp?.resources !== false },
@@ -1735,6 +1993,7 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1735
1993
  debug: config.debug || false,
1736
1994
  debugCron: config.debugCron || false,
1737
1995
  contentNegotiation: config.contentNegotiation === void 0 ? "auto" : config.contentNegotiation ? "enabled" : "disabled",
1996
+ botNegotiation: config.botNegotiation === true,
1738
1997
  mdreamOptions: config.mdreamOptions || {},
1739
1998
  sitemapMd: config.sitemapMd !== false,
1740
1999
  describedby: config.describedby !== false,
@@ -1759,35 +2018,38 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1759
2018
  apiCatalog: apiCatalogConfig
1760
2019
  };
1761
2020
  if (prerenderEnabled) {
1762
- addServerPlugin(resolve("./runtime/server/plugins/html-capture.prerender"));
2021
+ addNitroPlugin(resolve$1("./runtime/server/plugins/html-capture.prerender"));
1763
2022
  addServerHandler({
1764
2023
  middleware: true,
1765
- handler: resolve("./runtime/server/middleware/markdown.prerender")
2024
+ handler: resolve$1("./runtime/server/middleware/markdown.prerender")
1766
2025
  });
1767
2026
  addPlugin({
1768
2027
  mode: "server",
1769
- src: resolve("./runtime/app/plugins/md-hints.prerender")
2028
+ src: resolve$1("./runtime/app/plugins/md-hints.prerender")
1770
2029
  });
1771
2030
  }
1772
2031
  addServerHandler({
1773
2032
  middleware: true,
1774
- handler: resolve("./runtime/server/middleware/markdown")
2033
+ handler: resolve$1("./runtime/server/middleware/markdown")
1775
2034
  });
1776
- addServerPlugin(resolve("./runtime/server/plugins/link-header"));
1777
- addServerPlugin(resolve("./runtime/server/plugins/markdown-negotiation"));
2035
+ if (getNitroVersion(nuxt) === 3) {
2036
+ extendRouteRules("/**.md", { cache: false });
2037
+ }
2038
+ addNitroPlugin(resolve$1(getNitroVersion(nuxt) === 3 ? "./runtime/server/plugins/link-header-nitro3" : "./runtime/server/plugins/link-header"));
2039
+ addNitroPlugin(resolve$1("./runtime/server/plugins/markdown-negotiation"));
1778
2040
  addPlugin({
1779
2041
  mode: "server",
1780
- src: resolve("./runtime/app/plugins/md-alternate.server")
2042
+ src: resolve$1("./runtime/app/plugins/md-alternate.server")
1781
2043
  });
1782
- addServerHandler({ route: "/llms.txt", handler: resolve("./runtime/server/routes/llms.txt.get"), lazy: true });
1783
- addServerHandler({ route: "/llms-full.txt", handler: resolve("./runtime/server/routes/llms-full.txt.get"), lazy: true });
2044
+ addServerHandler({ route: "/llms.txt", handler: resolve$1("./runtime/server/routes/llms.txt.get"), lazy: true });
2045
+ addServerHandler({ route: "/llms-full.txt", handler: resolve$1("./runtime/server/routes/llms-full.txt.get"), lazy: true });
1784
2046
  if (config.sitemapMd !== false) {
1785
- addServerHandler({ route: SITEMAP_MD_ROUTE, handler: resolve("./runtime/server/routes/sitemap.md.get"), lazy: true });
2047
+ addServerHandler({ route: SITEMAP_MD_ROUTE, handler: resolve$1("./runtime/server/routes/sitemap.md.get"), lazy: true });
1786
2048
  }
1787
2049
  if (agentSkillsResult._tag === "Enabled") {
1788
- addServerHandler({ route: AGENT_SKILLS_INDEX_ROUTE, handler: resolve("./runtime/server/routes/agent-skills-index"), lazy: true });
2050
+ addServerHandler({ route: AGENT_SKILLS_INDEX_ROUTE, handler: resolve$1("./runtime/server/routes/agent-skills-index"), lazy: true });
1789
2051
  for (const route of Object.keys(agentSkillsResult.localArtifacts)) {
1790
- addServerHandler({ route, handler: resolve("./runtime/server/routes/agent-skills-artifact"), lazy: true });
2052
+ addServerHandler({ route, handler: resolve$1("./runtime/server/routes/agent-skills-artifact"), lazy: true });
1791
2053
  extendRouteRules(route, {
1792
2054
  headers: {
1793
2055
  "Content-Type": "text/markdown; charset=utf-8",
@@ -1820,39 +2082,38 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1820
2082
  if (webmcpConfig) {
1821
2083
  addImports(["useWebMcpSupported", "useWebMcpTool"].map((name) => ({
1822
2084
  name,
1823
- from: resolve("./runtime/app/composables/webmcp")
2085
+ from: resolve$1("./runtime/app/composables/webmcp")
1824
2086
  })));
1825
2087
  nuxt.options.runtimeConfig.public["nuxt-ai-ready"] = {
1826
2088
  webmcp: webmcpConfig
1827
2089
  };
1828
- addPlugin({ mode: "client", src: resolve("./runtime/app/plugins/webmcp.client") });
2090
+ addPlugin({ mode: "client", src: resolve$1("./runtime/app/plugins/webmcp.client") });
1829
2091
  if (Object.keys(webmcpConfig.tools).length) {
1830
- addServerHandler({ route: "/__ai-ready/pages", handler: resolve("./runtime/server/routes/__ai-ready/pages.get"), lazy: true });
2092
+ addServerHandler({ route: "/__ai-ready/pages", handler: resolve$1("./runtime/server/routes/__ai-ready/pages.get"), lazy: true });
1831
2093
  }
1832
2094
  }
1833
2095
  if (nuxt.options.dev || config.debug) {
1834
- addServerHandler({ route: "/__ai-ready__/debug.json", handler: resolve("./runtime/server/routes/__ai-ready/devtools.get"), lazy: true });
2096
+ addServerHandler({ route: "/__ai-ready__/debug.json", handler: resolve$1("./runtime/server/routes/__ai-ready/devtools.get"), lazy: true });
1835
2097
  }
1836
2098
  if (config.debug) {
1837
- addServerHandler({ route: "/__ai-ready-debug", handler: resolve("./runtime/server/routes/__ai-ready-debug.get"), lazy: true });
2099
+ addServerHandler({ route: "/__ai-ready-debug", handler: resolve$1("./runtime/server/routes/__ai-ready-debug.get"), lazy: true });
1838
2100
  }
1839
2101
  if (runtimeSyncEnabled) {
1840
- addServerHandler({ route: "/__ai-ready/status", handler: resolve("./runtime/server/routes/__ai-ready/status.get"), lazy: true });
1841
- addServerHandler({ route: "/__ai-ready/poll", method: "post", handler: resolve("./runtime/server/routes/__ai-ready/poll.post"), lazy: true });
1842
- addServerHandler({ route: "/__ai-ready/prune", method: "post", handler: resolve("./runtime/server/routes/__ai-ready/prune.post"), lazy: true });
1843
- addServerHandler({ route: "/__ai-ready/restore", method: "post", handler: resolve("./runtime/server/routes/__ai-ready/restore.post"), lazy: true });
1844
- addServerHandler({ route: "/__ai-ready/reindex", method: "post", handler: resolve("./runtime/server/routes/__ai-ready/reindex.post"), lazy: true });
1845
- addServerPlugin(resolve("./runtime/server/plugins/sitemap-seeder"));
2102
+ addServerHandler({ route: "/__ai-ready/status", handler: resolve$1("./runtime/server/routes/__ai-ready/status.get"), lazy: true });
2103
+ addServerHandler({ route: "/__ai-ready/poll", method: "post", handler: resolve$1("./runtime/server/routes/__ai-ready/poll.post"), lazy: true });
2104
+ addServerHandler({ route: "/__ai-ready/prune", method: "post", handler: resolve$1("./runtime/server/routes/__ai-ready/prune.post"), lazy: true });
2105
+ addServerHandler({ route: "/__ai-ready/restore", method: "post", handler: resolve$1("./runtime/server/routes/__ai-ready/restore.post"), lazy: true });
2106
+ addServerHandler({ route: "/__ai-ready/reindex", method: "post", handler: resolve$1("./runtime/server/routes/__ai-ready/reindex.post"), lazy: true });
2107
+ addNitroPlugin(resolve$1("./runtime/server/plugins/sitemap-seeder"));
1846
2108
  }
1847
2109
  if (config.cron && !nuxt.options.dev) {
1848
- addServerHandler({ route: "/__ai-ready/cron", handler: resolve("./runtime/server/routes/__ai-ready/cron.get"), lazy: true });
2110
+ addServerHandler({ route: "/__ai-ready/cron", handler: resolve$1("./runtime/server/routes/__ai-ready/cron.get"), lazy: true });
1849
2111
  }
1850
2112
  if (apiCatalogConfig)
1851
2113
  registerApiCatalog(apiCatalogConfig);
1852
2114
  if (!nuxt.options.dev && !nuxt.options._prepare) {
1853
2115
  if (isSPA && !hasPrerenderedRoutes) {
1854
2116
  logger.warn("SPA mode detected without prerendering. llms-full.txt will not be generated.");
1855
- logger.warn("For full functionality, enable SSR or prerender routes.");
1856
2117
  } else if (!isStatic && !hasPrerenderedRoutes) {
1857
2118
  logger.info("SSR-only mode: llms-full.txt requires prerendering. Runtime markdown conversion available.");
1858
2119
  }
@@ -1869,8 +2130,9 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1869
2130
  artifactRoutes: agentSkillsResult._tag === "Enabled" ? Object.keys(agentSkillsResult.localArtifacts) : []
1870
2131
  });
1871
2132
  }
1872
- if (databaseEnabled)
1873
- addServerPlugin(resolve("./runtime/server/plugins/db-lifecycle"));
2133
+ if (databaseEnabled) {
2134
+ addNitroPlugin(resolve$1(getNitroVersion(nuxt) === 3 ? "./runtime/server/plugins/db-lifecycle-nitro3" : "./runtime/server/plugins/db-lifecycle"));
2135
+ }
1874
2136
  if (nuxt.options.dev) {
1875
2137
  const { setupDevToolsUI } = await import('nuxtseo-shared/devtools');
1876
2138
  setupDevToolsUI({
@@ -1878,7 +2140,7 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1878
2140
  name: "nuxt-ai-ready",
1879
2141
  title: "AI Ready",
1880
2142
  icon: "carbon:ai-label"
1881
- }, resolve, nuxt);
2143
+ }, resolve$1, nuxt);
1882
2144
  }
1883
2145
  for (const route of ["/llms.txt", "/llms-full.txt"]) {
1884
2146
  extendRouteRules(route, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
@@ -1887,19 +2149,59 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1887
2149
  extendRouteRules(SITEMAP_MD_ROUTE, { headers: { "Content-Type": "text/markdown; charset=utf-8" } });
1888
2150
  }
1889
2151
  const staticBaseURL = nuxt.options.app.baseURL || "/";
2152
+ const emittedWarnings = /* @__PURE__ */ new Set();
2153
+ const warnConfiguration = (nitro) => {
2154
+ if (preparing)
2155
+ return;
2156
+ const warnings = resolveConfigurationWarnings({
2157
+ policy: nuxt.options.runtimeConfig["nuxt-ai-ready"].contentNegotiation,
2158
+ botNegotiation: config.botNegotiation === true,
2159
+ static: nitro.options.static === true || isStatic,
2160
+ siteUrl: siteConfig.url || void 0,
2161
+ routeRules: nitro.options.routeRules
2162
+ });
2163
+ for (const warning of warnings) {
2164
+ if (!emittedWarnings.has(warning)) {
2165
+ emittedWarnings.add(warning);
2166
+ logger.warn(warning);
2167
+ }
2168
+ }
2169
+ };
2170
+ nuxt.hook("nitro:init", (nitro) => {
2171
+ warnConfiguration(nitro);
2172
+ nitro.hooks.hook("rollup:reload", () => warnConfiguration(nitro));
2173
+ });
2174
+ nuxt.hook("nitro:build:before", warnConfiguration);
1890
2175
  for (const route of nuxt.options.nitro.prerender?.routes || []) {
1891
2176
  if (!isStaticMarkdownSourceRoute(route))
1892
2177
  continue;
1893
2178
  extendRouteRules(toMarkdownPath(route), {
1894
2179
  headers: {
1895
2180
  "Content-Type": "text/markdown; charset=utf-8",
1896
- "Link": buildStaticMarkdownLinkHeader(route, staticBaseURL, config.describedby !== false)
2181
+ "Link": buildStaticMarkdownLinkHeader(route, staticBaseURL, config.describedby !== false),
2182
+ "Vary": "Accept"
1897
2183
  }
1898
2184
  });
1899
2185
  }
1900
2186
  nuxt.hooks.hook("nitro:build:before", (nitro) => {
1901
2187
  const isCloudflarePreset = String(nitro.options.preset || "").startsWith("cloudflare");
1902
- nitro.hooks.hook("prerender:done", () => {
2188
+ nitro.hooks.hook("prerender:done", async () => {
2189
+ if (["cloudflare", "cloudflare-module", "cloudflare-durable"].includes(String(nitro.options.preset)) && !nitro.options.static && config.contentNegotiation === true) {
2190
+ const pages = cloudflarePrerenderedPages(nitro._prerenderedRoutes || [], staticBaseURL);
2191
+ const cloudflare = nitro.options.cloudflare ||= {};
2192
+ const wrangler = cloudflare.wrangler ||= {};
2193
+ const assets = wrangler.assets ||= {};
2194
+ const fileRouting = await readCloudflareAssetRouting(nitro.options.rootDir);
2195
+ const routing = defu$1({ value: assets.run_worker_first }, { value: fileRouting.root }).value;
2196
+ cloudflareNegotiationPatterns(routing, pages);
2197
+ const environmentConfig = wrangler;
2198
+ const configuredEnvironments = Object.values(environmentConfig.env || {}).flatMap((env) => env.assets?.run_worker_first === void 0 ? [] : [env.assets.run_worker_first]);
2199
+ const fallbackPaths = cloudflareStaticFallbackPaths(routing, pages, [...fileRouting.environments, ...configuredEnvironments]);
2200
+ const addedPaths = cloudflareStaticFallbackPaths(routing, pages);
2201
+ if (addedPaths.length > 0)
2202
+ assets.run_worker_first = [...Array.isArray(assets.run_worker_first) ? assets.run_worker_first : [], ...addedPaths];
2203
+ nitro.options.runtimeConfig["nuxt-ai-ready"].cloudflarePrerenderedPages = fallbackPaths;
2204
+ }
1903
2205
  const plan = planStaticMarkdownHeaderRules(
1904
2206
  nitro.options.routeRules,
1905
2207
  prerenderedMarkdownHeaderRules(
@@ -1918,26 +2220,65 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1918
2220
  applyStaticMarkdownHeaderPlan(nitro.options.routeRules, plan);
1919
2221
  });
1920
2222
  nitro.hooks.hook("compiled", async () => {
1921
- const headersPath = join(nitro.options.output.publicDir, "_headers");
2223
+ const generatedHeadersPath = join(nitro.options.output.publicDir, "_headers");
2224
+ let headersPath = generatedHeadersPath;
2225
+ let staticDiscoverySupported = isCloudflarePreset;
2226
+ if (isCloudflarePreset) {
2227
+ const wranglerPath = join(nitro.options.output.serverDir, "wrangler.json");
2228
+ const wrangler = await readFile(wranglerPath, "utf8").then((contents) => JSON.parse(contents)).catch((error) => {
2229
+ if (error.code === "ENOENT")
2230
+ return void 0;
2231
+ throw error;
2232
+ });
2233
+ const assetsDirectory = wrangler?.assets?.directory || wrangler?.pages_build_output_dir;
2234
+ const assetsRoot = assetsDirectory ? resolve(dirname(wranglerPath), assetsDirectory) : String(nitro.options.preset).startsWith("cloudflare-pages") ? nitro.options.output.dir : resolve(nitro.options.output.publicDir, ...staticBaseURL.split("/").filter(Boolean).map(() => ".."));
2235
+ const assetPath = relative(nitro.options.output.dir, assetsRoot);
2236
+ if (assetPath === ".." || assetPath.startsWith("../")) {
2237
+ staticDiscoverySupported = false;
2238
+ logger.warn("Skipped shared discovery headers because Cloudflare assets are outside the Nitro output directory.");
2239
+ } else {
2240
+ headersPath = join(assetsRoot, "_headers");
2241
+ }
2242
+ }
1922
2243
  logger.debug(`Checking for _headers file: ${headersPath}`);
1923
2244
  const exists = await access(headersPath).then(() => true).catch(() => false);
1924
- if (exists) {
1925
- const headers = await readFile(headersPath, "utf8");
2245
+ if (exists || isCloudflarePreset) {
2246
+ const readHeaders = (path) => readFile(path, "utf8").catch((error) => {
2247
+ if (error.code === "ENOENT")
2248
+ return "";
2249
+ throw error;
2250
+ });
2251
+ const rootHeaders = exists ? await readHeaders(headersPath) : "";
2252
+ const generatedHeaders = generatedHeadersPath === headersPath ? "" : await readHeaders(generatedHeadersPath);
2253
+ const headers = [rootHeaders, generatedHeaders].filter(Boolean).join("\n");
2254
+ const markdownPattern = isCloudflarePreset ? toDeployedRoute("/*.md", staticBaseURL) : "/*.md";
1926
2255
  let mergedHeaders = ensureStaticHeader(
1927
2256
  headers,
1928
- "/*.md",
2257
+ markdownPattern,
1929
2258
  "Content-Type",
1930
2259
  "text/markdown; charset=utf-8"
1931
2260
  );
2261
+ mergedHeaders = ensureStaticHeader(mergedHeaders, markdownPattern, "Vary", "Accept", "append");
1932
2262
  if (config.describedby !== false) {
1933
2263
  mergedHeaders = ensureStaticHeader(
1934
2264
  mergedHeaders,
1935
- "/*.md",
2265
+ markdownPattern,
1936
2266
  "Link",
1937
2267
  staticDescribedbyEntry(nitro.options.baseURL || "/")
1938
2268
  );
1939
2269
  }
1940
2270
  if (isCloudflarePreset) {
2271
+ const hasArtifact = (route) => access(join(nitro.options.output.publicDir, route)).then(() => true).catch((error) => {
2272
+ if (error.code === "ENOENT")
2273
+ return false;
2274
+ throw error;
2275
+ });
2276
+ const discovery = [];
2277
+ if (staticDiscoverySupported && config.describedby !== false && await hasArtifact("/llms.txt"))
2278
+ discovery.push(staticDescribedbyEntry(staticBaseURL));
2279
+ if (staticDiscoverySupported && apiCatalogConfig && await hasArtifact(API_CATALOG_PATH))
2280
+ discovery.push(`<${encodeURI(apiCatalogConfig.href)}>; rel="api-catalog"`);
2281
+ mergedHeaders = mergeStaticDiscoveryHeaders(mergedHeaders, staticBaseURL, discovery);
1941
2282
  const budget = enforceStaticHeaderBudget(mergedHeaders, CLOUDFLARE_STATIC_HEADER_RULE_LIMIT);
1942
2283
  if (budget.dropped > 0) {
1943
2284
  mergedHeaders = budget.contents;
@@ -1946,7 +2287,7 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1946
2287
  if (budget.total > CLOUDFLARE_STATIC_HEADER_RULE_LIMIT)
1947
2288
  logger.warn(`_headers still has ${budget.total} rules after dropping the .md rules. Cloudflare will reject the deploy until the other rules fit under ${CLOUDFLARE_STATIC_HEADER_RULE_LIMIT}.`);
1948
2289
  }
1949
- if (mergedHeaders !== headers) {
2290
+ if (mergedHeaders !== rootHeaders || !exists) {
1950
2291
  await writeFile(headersPath, mergedHeaders);
1951
2292
  logger.debug("Merged .md charset header into _headers");
1952
2293
  }
@@ -1956,4 +2297,4 @@ export const logger = createModuleLogger('nuxt-ai-ready', ${!!config.debug})
1956
2297
  }
1957
2298
  });
1958
2299
 
1959
- export { AGENT_SKILLS_SCHEMA as A, MARKDOWN_LINK_AVAILABILITY_FILE as M, logger as l, module$1 as m, supportsNativeNodeSqlite as s };
2300
+ export { AGENT_SKILLS_SCHEMA as A, MARKDOWN_LINK_AVAILABILITY_FILE as M, logger as l, module$1 as m };