@prenta/core 0.118.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 (1408) hide show
  1. package/CHANGELOG.md +2974 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -0
  4. package/dist/a11y/index.d.ts +25 -0
  5. package/dist/a11y/index.d.ts.map +1 -0
  6. package/dist/a11y/index.js +91 -0
  7. package/dist/a11y/index.js.map +1 -0
  8. package/dist/actions.d.ts +130 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +1324 -0
  11. package/dist/actions.js.map +1 -0
  12. package/dist/ai/brand-voice-alignment.d.ts +17 -0
  13. package/dist/ai/brand-voice-alignment.d.ts.map +1 -0
  14. package/dist/ai/brand-voice-alignment.js +40 -0
  15. package/dist/ai/brand-voice-alignment.js.map +1 -0
  16. package/dist/ai/brand-voice-analyze.d.ts +71 -0
  17. package/dist/ai/brand-voice-analyze.d.ts.map +1 -0
  18. package/dist/ai/brand-voice-analyze.js +151 -0
  19. package/dist/ai/brand-voice-analyze.js.map +1 -0
  20. package/dist/ai/brand-voice-document.d.ts +56 -0
  21. package/dist/ai/brand-voice-document.d.ts.map +1 -0
  22. package/dist/ai/brand-voice-document.js +335 -0
  23. package/dist/ai/brand-voice-document.js.map +1 -0
  24. package/dist/ai/brand-voice-fix.d.ts +26 -0
  25. package/dist/ai/brand-voice-fix.d.ts.map +1 -0
  26. package/dist/ai/brand-voice-fix.js +97 -0
  27. package/dist/ai/brand-voice-fix.js.map +1 -0
  28. package/dist/ai/brand-voice-save.d.ts +11 -0
  29. package/dist/ai/brand-voice-save.d.ts.map +1 -0
  30. package/dist/ai/brand-voice-save.js +51 -0
  31. package/dist/ai/brand-voice-save.js.map +1 -0
  32. package/dist/ai/brand-voice-sources.d.ts +16 -0
  33. package/dist/ai/brand-voice-sources.d.ts.map +1 -0
  34. package/dist/ai/brand-voice-sources.js +106 -0
  35. package/dist/ai/brand-voice-sources.js.map +1 -0
  36. package/dist/ai/brand-voice-structured.d.ts +87 -0
  37. package/dist/ai/brand-voice-structured.d.ts.map +1 -0
  38. package/dist/ai/brand-voice-structured.js +438 -0
  39. package/dist/ai/brand-voice-structured.js.map +1 -0
  40. package/dist/ai/brand-voice.d.ts +40 -0
  41. package/dist/ai/brand-voice.d.ts.map +1 -0
  42. package/dist/ai/brand-voice.js +103 -0
  43. package/dist/ai/brand-voice.js.map +1 -0
  44. package/dist/ai/catalog.d.ts +35 -0
  45. package/dist/ai/catalog.d.ts.map +1 -0
  46. package/dist/ai/catalog.js +370 -0
  47. package/dist/ai/catalog.js.map +1 -0
  48. package/dist/ai/config-store.d.ts +55 -0
  49. package/dist/ai/config-store.d.ts.map +1 -0
  50. package/dist/ai/config-store.js +177 -0
  51. package/dist/ai/config-store.js.map +1 -0
  52. package/dist/ai/content-writing-generate.d.ts +19 -0
  53. package/dist/ai/content-writing-generate.d.ts.map +1 -0
  54. package/dist/ai/content-writing-generate.js +64 -0
  55. package/dist/ai/content-writing-generate.js.map +1 -0
  56. package/dist/ai/feature-defaults.d.ts +20 -0
  57. package/dist/ai/feature-defaults.d.ts.map +1 -0
  58. package/dist/ai/feature-defaults.js +104 -0
  59. package/dist/ai/feature-defaults.js.map +1 -0
  60. package/dist/ai/index.d.ts +24 -0
  61. package/dist/ai/index.d.ts.map +1 -0
  62. package/dist/ai/index.js +24 -0
  63. package/dist/ai/index.js.map +1 -0
  64. package/dist/ai/models.d.ts +37 -0
  65. package/dist/ai/models.d.ts.map +1 -0
  66. package/dist/ai/models.js +126 -0
  67. package/dist/ai/models.js.map +1 -0
  68. package/dist/ai/providers/anthropic.d.ts +10 -0
  69. package/dist/ai/providers/anthropic.d.ts.map +1 -0
  70. package/dist/ai/providers/anthropic.js +63 -0
  71. package/dist/ai/providers/anthropic.js.map +1 -0
  72. package/dist/ai/providers/custom.d.ts +12 -0
  73. package/dist/ai/providers/custom.d.ts.map +1 -0
  74. package/dist/ai/providers/custom.js +76 -0
  75. package/dist/ai/providers/custom.js.map +1 -0
  76. package/dist/ai/providers/http.d.ts +66 -0
  77. package/dist/ai/providers/http.d.ts.map +1 -0
  78. package/dist/ai/providers/http.js +185 -0
  79. package/dist/ai/providers/http.js.map +1 -0
  80. package/dist/ai/providers/index.d.ts +18 -0
  81. package/dist/ai/providers/index.d.ts.map +1 -0
  82. package/dist/ai/providers/index.js +28 -0
  83. package/dist/ai/providers/index.js.map +1 -0
  84. package/dist/ai/providers/openai.d.ts +11 -0
  85. package/dist/ai/providers/openai.d.ts.map +1 -0
  86. package/dist/ai/providers/openai.js +44 -0
  87. package/dist/ai/providers/openai.js.map +1 -0
  88. package/dist/ai/providers/xai.d.ts +10 -0
  89. package/dist/ai/providers/xai.d.ts.map +1 -0
  90. package/dist/ai/providers/xai.js +38 -0
  91. package/dist/ai/providers/xai.js.map +1 -0
  92. package/dist/ai/resolve.d.ts +41 -0
  93. package/dist/ai/resolve.d.ts.map +1 -0
  94. package/dist/ai/resolve.js +143 -0
  95. package/dist/ai/resolve.js.map +1 -0
  96. package/dist/ai/runtime.d.ts +88 -0
  97. package/dist/ai/runtime.d.ts.map +1 -0
  98. package/dist/ai/runtime.js +192 -0
  99. package/dist/ai/runtime.js.map +1 -0
  100. package/dist/ai/sampling.d.ts +17 -0
  101. package/dist/ai/sampling.d.ts.map +1 -0
  102. package/dist/ai/sampling.js +51 -0
  103. package/dist/ai/sampling.js.map +1 -0
  104. package/dist/ai/types.d.ts +193 -0
  105. package/dist/ai/types.d.ts.map +1 -0
  106. package/dist/ai/types.js +11 -0
  107. package/dist/ai/types.js.map +1 -0
  108. package/dist/ai/usage.d.ts +18 -0
  109. package/dist/ai/usage.d.ts.map +1 -0
  110. package/dist/ai/usage.js +70 -0
  111. package/dist/ai/usage.js.map +1 -0
  112. package/dist/api/collection-introspection.d.ts +46 -0
  113. package/dist/api/collection-introspection.d.ts.map +1 -0
  114. package/dist/api/collection-introspection.js +82 -0
  115. package/dist/api/collection-introspection.js.map +1 -0
  116. package/dist/api/guarded-db.d.ts +14 -0
  117. package/dist/api/guarded-db.d.ts.map +1 -0
  118. package/dist/api/guarded-db.js +62 -0
  119. package/dist/api/guarded-db.js.map +1 -0
  120. package/dist/api/handler-factory.d.ts +7 -0
  121. package/dist/api/handler-factory.d.ts.map +1 -0
  122. package/dist/api/handler-factory.js +380 -0
  123. package/dist/api/handler-factory.js.map +1 -0
  124. package/dist/api/handlers.d.ts +8 -0
  125. package/dist/api/handlers.d.ts.map +1 -0
  126. package/dist/api/handlers.js +62 -0
  127. package/dist/api/handlers.js.map +1 -0
  128. package/dist/api/index.d.ts +8 -0
  129. package/dist/api/index.d.ts.map +1 -0
  130. package/dist/api/index.js +8 -0
  131. package/dist/api/index.js.map +1 -0
  132. package/dist/api/openapi.d.ts +3 -0
  133. package/dist/api/openapi.d.ts.map +1 -0
  134. package/dist/api/openapi.js +539 -0
  135. package/dist/api/openapi.js.map +1 -0
  136. package/dist/api/route-helpers.d.ts +369 -0
  137. package/dist/api/route-helpers.d.ts.map +1 -0
  138. package/dist/api/route-helpers.js +1574 -0
  139. package/dist/api/route-helpers.js.map +1 -0
  140. package/dist/api/router.d.ts +21 -0
  141. package/dist/api/router.d.ts.map +1 -0
  142. package/dist/api/router.js +75 -0
  143. package/dist/api/router.js.map +1 -0
  144. package/dist/api/routes/ai-seo.d.ts +3 -0
  145. package/dist/api/routes/ai-seo.d.ts.map +1 -0
  146. package/dist/api/routes/ai-seo.js +482 -0
  147. package/dist/api/routes/ai-seo.js.map +1 -0
  148. package/dist/api/routes/ai-settings.d.ts +3 -0
  149. package/dist/api/routes/ai-settings.d.ts.map +1 -0
  150. package/dist/api/routes/ai-settings.js +1078 -0
  151. package/dist/api/routes/ai-settings.js.map +1 -0
  152. package/dist/api/routes/auth.d.ts +3 -0
  153. package/dist/api/routes/auth.d.ts.map +1 -0
  154. package/dist/api/routes/auth.js +877 -0
  155. package/dist/api/routes/auth.js.map +1 -0
  156. package/dist/api/routes/collab.d.ts +3 -0
  157. package/dist/api/routes/collab.d.ts.map +1 -0
  158. package/dist/api/routes/collab.js +426 -0
  159. package/dist/api/routes/collab.js.map +1 -0
  160. package/dist/api/routes/dashboard.d.ts +7 -0
  161. package/dist/api/routes/dashboard.d.ts.map +1 -0
  162. package/dist/api/routes/dashboard.js +540 -0
  163. package/dist/api/routes/dashboard.js.map +1 -0
  164. package/dist/api/routes/documents.d.ts +11 -0
  165. package/dist/api/routes/documents.d.ts.map +1 -0
  166. package/dist/api/routes/documents.js +340 -0
  167. package/dist/api/routes/documents.js.map +1 -0
  168. package/dist/api/routes/email-settings.d.ts +3 -0
  169. package/dist/api/routes/email-settings.d.ts.map +1 -0
  170. package/dist/api/routes/email-settings.js +248 -0
  171. package/dist/api/routes/email-settings.js.map +1 -0
  172. package/dist/api/routes/folders.d.ts +3 -0
  173. package/dist/api/routes/folders.d.ts.map +1 -0
  174. package/dist/api/routes/folders.js +195 -0
  175. package/dist/api/routes/folders.js.map +1 -0
  176. package/dist/api/routes/forms.d.ts +3 -0
  177. package/dist/api/routes/forms.d.ts.map +1 -0
  178. package/dist/api/routes/forms.js +776 -0
  179. package/dist/api/routes/forms.js.map +1 -0
  180. package/dist/api/routes/globals.d.ts +3 -0
  181. package/dist/api/routes/globals.d.ts.map +1 -0
  182. package/dist/api/routes/globals.js +157 -0
  183. package/dist/api/routes/globals.js.map +1 -0
  184. package/dist/api/routes/media.d.ts +3 -0
  185. package/dist/api/routes/media.d.ts.map +1 -0
  186. package/dist/api/routes/media.js +807 -0
  187. package/dist/api/routes/media.js.map +1 -0
  188. package/dist/api/routes/meta.d.ts +3 -0
  189. package/dist/api/routes/meta.d.ts.map +1 -0
  190. package/dist/api/routes/meta.js +97 -0
  191. package/dist/api/routes/meta.js.map +1 -0
  192. package/dist/api/routes/navigations.d.ts +7 -0
  193. package/dist/api/routes/navigations.d.ts.map +1 -0
  194. package/dist/api/routes/navigations.js +81 -0
  195. package/dist/api/routes/navigations.js.map +1 -0
  196. package/dist/api/routes/page-templates.d.ts +3 -0
  197. package/dist/api/routes/page-templates.d.ts.map +1 -0
  198. package/dist/api/routes/page-templates.js +265 -0
  199. package/dist/api/routes/page-templates.js.map +1 -0
  200. package/dist/api/routes/presence.d.ts +3 -0
  201. package/dist/api/routes/presence.d.ts.map +1 -0
  202. package/dist/api/routes/presence.js +35 -0
  203. package/dist/api/routes/presence.js.map +1 -0
  204. package/dist/api/routes/preview.d.ts +3 -0
  205. package/dist/api/routes/preview.d.ts.map +1 -0
  206. package/dist/api/routes/preview.js +111 -0
  207. package/dist/api/routes/preview.js.map +1 -0
  208. package/dist/api/routes/redirects.d.ts +3 -0
  209. package/dist/api/routes/redirects.d.ts.map +1 -0
  210. package/dist/api/routes/redirects.js +937 -0
  211. package/dist/api/routes/redirects.js.map +1 -0
  212. package/dist/api/routes/saved-sections.d.ts +3 -0
  213. package/dist/api/routes/saved-sections.d.ts.map +1 -0
  214. package/dist/api/routes/saved-sections.js +1071 -0
  215. package/dist/api/routes/saved-sections.js.map +1 -0
  216. package/dist/api/routes/scheduling.d.ts +3 -0
  217. package/dist/api/routes/scheduling.d.ts.map +1 -0
  218. package/dist/api/routes/scheduling.js +391 -0
  219. package/dist/api/routes/scheduling.js.map +1 -0
  220. package/dist/api/routes/sections.d.ts +3 -0
  221. package/dist/api/routes/sections.d.ts.map +1 -0
  222. package/dist/api/routes/sections.js +512 -0
  223. package/dist/api/routes/sections.js.map +1 -0
  224. package/dist/api/routes/security-center.d.ts +3 -0
  225. package/dist/api/routes/security-center.d.ts.map +1 -0
  226. package/dist/api/routes/security-center.js +71 -0
  227. package/dist/api/routes/security-center.js.map +1 -0
  228. package/dist/api/routes/seo-public.d.ts +14 -0
  229. package/dist/api/routes/seo-public.d.ts.map +1 -0
  230. package/dist/api/routes/seo-public.js +1366 -0
  231. package/dist/api/routes/seo-public.js.map +1 -0
  232. package/dist/api/routes/seo.d.ts +8 -0
  233. package/dist/api/routes/seo.d.ts.map +1 -0
  234. package/dist/api/routes/seo.js +2256 -0
  235. package/dist/api/routes/seo.js.map +1 -0
  236. package/dist/api/routes/system.d.ts +3 -0
  237. package/dist/api/routes/system.d.ts.map +1 -0
  238. package/dist/api/routes/system.js +353 -0
  239. package/dist/api/routes/system.js.map +1 -0
  240. package/dist/api/routes/url-resolution.d.ts +3 -0
  241. package/dist/api/routes/url-resolution.d.ts.map +1 -0
  242. package/dist/api/routes/url-resolution.js +522 -0
  243. package/dist/api/routes/url-resolution.js.map +1 -0
  244. package/dist/api/routes/users.d.ts +3 -0
  245. package/dist/api/routes/users.d.ts.map +1 -0
  246. package/dist/api/routes/users.js +1177 -0
  247. package/dist/api/routes/users.js.map +1 -0
  248. package/dist/api/routes/webhooks.d.ts +3 -0
  249. package/dist/api/routes/webhooks.d.ts.map +1 -0
  250. package/dist/api/routes/webhooks.js +422 -0
  251. package/dist/api/routes/webhooks.js.map +1 -0
  252. package/dist/appearance/color.d.ts +24 -0
  253. package/dist/appearance/color.d.ts.map +1 -0
  254. package/dist/appearance/color.js +90 -0
  255. package/dist/appearance/color.js.map +1 -0
  256. package/dist/appearance/favicon-icon.d.ts +12 -0
  257. package/dist/appearance/favicon-icon.d.ts.map +1 -0
  258. package/dist/appearance/favicon-icon.js +58 -0
  259. package/dist/appearance/favicon-icon.js.map +1 -0
  260. package/dist/appearance/favicon-paths.d.ts +6 -0
  261. package/dist/appearance/favicon-paths.d.ts.map +1 -0
  262. package/dist/appearance/favicon-paths.js +6 -0
  263. package/dist/appearance/favicon-paths.js.map +1 -0
  264. package/dist/appearance/index.d.ts +15 -0
  265. package/dist/appearance/index.d.ts.map +1 -0
  266. package/dist/appearance/index.js +7 -0
  267. package/dist/appearance/index.js.map +1 -0
  268. package/dist/appearance/logo-shape.d.ts +26 -0
  269. package/dist/appearance/logo-shape.d.ts.map +1 -0
  270. package/dist/appearance/logo-shape.js +62 -0
  271. package/dist/appearance/logo-shape.js.map +1 -0
  272. package/dist/appearance/resolve.d.ts +52 -0
  273. package/dist/appearance/resolve.d.ts.map +1 -0
  274. package/dist/appearance/resolve.js +219 -0
  275. package/dist/appearance/resolve.js.map +1 -0
  276. package/dist/appearance/theme-tokens.d.ts +49 -0
  277. package/dist/appearance/theme-tokens.d.ts.map +1 -0
  278. package/dist/appearance/theme-tokens.js +229 -0
  279. package/dist/appearance/theme-tokens.js.map +1 -0
  280. package/dist/appearance/types.d.ts +110 -0
  281. package/dist/appearance/types.d.ts.map +1 -0
  282. package/dist/appearance/types.js +16 -0
  283. package/dist/appearance/types.js.map +1 -0
  284. package/dist/astro-cache.d.ts +80 -0
  285. package/dist/astro-cache.d.ts.map +1 -0
  286. package/dist/astro-cache.js +108 -0
  287. package/dist/astro-cache.js.map +1 -0
  288. package/dist/astro-content.d.ts +81 -0
  289. package/dist/astro-content.d.ts.map +1 -0
  290. package/dist/astro-content.js +151 -0
  291. package/dist/astro-content.js.map +1 -0
  292. package/dist/astro-redirects.d.ts +38 -0
  293. package/dist/astro-redirects.d.ts.map +1 -0
  294. package/dist/astro-redirects.js +45 -0
  295. package/dist/astro-redirects.js.map +1 -0
  296. package/dist/astro-security.d.ts +34 -0
  297. package/dist/astro-security.d.ts.map +1 -0
  298. package/dist/astro-security.js +31 -0
  299. package/dist/astro-security.js.map +1 -0
  300. package/dist/astro-site.d.ts +69 -0
  301. package/dist/astro-site.d.ts.map +1 -0
  302. package/dist/astro-site.js +81 -0
  303. package/dist/astro-site.js.map +1 -0
  304. package/dist/auth/index.d.ts +17 -0
  305. package/dist/auth/index.d.ts.map +1 -0
  306. package/dist/auth/index.js +12 -0
  307. package/dist/auth/index.js.map +1 -0
  308. package/dist/auth/invite-email.d.ts +12 -0
  309. package/dist/auth/invite-email.d.ts.map +1 -0
  310. package/dist/auth/invite-email.js +57 -0
  311. package/dist/auth/invite-email.js.map +1 -0
  312. package/dist/auth/invites.d.ts +72 -0
  313. package/dist/auth/invites.d.ts.map +1 -0
  314. package/dist/auth/invites.js +279 -0
  315. package/dist/auth/invites.js.map +1 -0
  316. package/dist/auth/mfa-pending.d.ts +24 -0
  317. package/dist/auth/mfa-pending.d.ts.map +1 -0
  318. package/dist/auth/mfa-pending.js +38 -0
  319. package/dist/auth/mfa-pending.js.map +1 -0
  320. package/dist/auth/oauth.d.ts +139 -0
  321. package/dist/auth/oauth.d.ts.map +1 -0
  322. package/dist/auth/oauth.js +376 -0
  323. package/dist/auth/oauth.js.map +1 -0
  324. package/dist/auth/password.d.ts +57 -0
  325. package/dist/auth/password.d.ts.map +1 -0
  326. package/dist/auth/password.js +150 -0
  327. package/dist/auth/password.js.map +1 -0
  328. package/dist/auth/providers/github.d.ts +9 -0
  329. package/dist/auth/providers/github.d.ts.map +1 -0
  330. package/dist/auth/providers/github.js +10 -0
  331. package/dist/auth/providers/github.js.map +1 -0
  332. package/dist/auth/providers/google.d.ts +9 -0
  333. package/dist/auth/providers/google.d.ts.map +1 -0
  334. package/dist/auth/providers/google.js +10 -0
  335. package/dist/auth/providers/google.js.map +1 -0
  336. package/dist/auth/providers/microsoft.d.ts +9 -0
  337. package/dist/auth/providers/microsoft.d.ts.map +1 -0
  338. package/dist/auth/providers/microsoft.js +11 -0
  339. package/dist/auth/providers/microsoft.js.map +1 -0
  340. package/dist/auth/reset-email.d.ts +10 -0
  341. package/dist/auth/reset-email.d.ts.map +1 -0
  342. package/dist/auth/reset-email.js +30 -0
  343. package/dist/auth/reset-email.js.map +1 -0
  344. package/dist/auth/reset.d.ts +42 -0
  345. package/dist/auth/reset.d.ts.map +1 -0
  346. package/dist/auth/reset.js +142 -0
  347. package/dist/auth/reset.js.map +1 -0
  348. package/dist/auth/roles.d.ts +51 -0
  349. package/dist/auth/roles.d.ts.map +1 -0
  350. package/dist/auth/roles.js +159 -0
  351. package/dist/auth/roles.js.map +1 -0
  352. package/dist/auth/session.d.ts +38 -0
  353. package/dist/auth/session.d.ts.map +1 -0
  354. package/dist/auth/session.js +106 -0
  355. package/dist/auth/session.js.map +1 -0
  356. package/dist/auth/team.d.ts +99 -0
  357. package/dist/auth/team.d.ts.map +1 -0
  358. package/dist/auth/team.js +327 -0
  359. package/dist/auth/team.js.map +1 -0
  360. package/dist/auth/totp.d.ts +31 -0
  361. package/dist/auth/totp.d.ts.map +1 -0
  362. package/dist/auth/totp.js +134 -0
  363. package/dist/auth/totp.js.map +1 -0
  364. package/dist/auth/user-admin.d.ts +119 -0
  365. package/dist/auth/user-admin.d.ts.map +1 -0
  366. package/dist/auth/user-admin.js +292 -0
  367. package/dist/auth/user-admin.js.map +1 -0
  368. package/dist/backup/index.d.ts +19 -0
  369. package/dist/backup/index.d.ts.map +1 -0
  370. package/dist/backup/index.js +24 -0
  371. package/dist/backup/index.js.map +1 -0
  372. package/dist/billing/stripe-meter.d.ts +22 -0
  373. package/dist/billing/stripe-meter.d.ts.map +1 -0
  374. package/dist/billing/stripe-meter.js +101 -0
  375. package/dist/billing/stripe-meter.js.map +1 -0
  376. package/dist/brand-voice/index.d.ts +7 -0
  377. package/dist/brand-voice/index.d.ts.map +1 -0
  378. package/dist/brand-voice/index.js +7 -0
  379. package/dist/brand-voice/index.js.map +1 -0
  380. package/dist/cache/http.d.ts +140 -0
  381. package/dist/cache/http.d.ts.map +1 -0
  382. package/dist/cache/http.js +213 -0
  383. package/dist/cache/http.js.map +1 -0
  384. package/dist/cache/index.d.ts +15 -0
  385. package/dist/cache/index.d.ts.map +1 -0
  386. package/dist/cache/index.js +32 -0
  387. package/dist/cache/index.js.map +1 -0
  388. package/dist/client.d.ts +51 -0
  389. package/dist/client.d.ts.map +1 -0
  390. package/dist/client.js +59 -0
  391. package/dist/client.js.map +1 -0
  392. package/dist/codegen/index.d.ts +4 -0
  393. package/dist/codegen/index.d.ts.map +1 -0
  394. package/dist/codegen/index.js +366 -0
  395. package/dist/codegen/index.js.map +1 -0
  396. package/dist/collections/index.d.ts +19 -0
  397. package/dist/collections/index.d.ts.map +1 -0
  398. package/dist/collections/index.js +30 -0
  399. package/dist/collections/index.js.map +1 -0
  400. package/dist/collections/presets.d.ts +90 -0
  401. package/dist/collections/presets.d.ts.map +1 -0
  402. package/dist/collections/presets.js +573 -0
  403. package/dist/collections/presets.js.map +1 -0
  404. package/dist/config/define.d.ts +8 -0
  405. package/dist/config/define.d.ts.map +1 -0
  406. package/dist/config/define.js +7 -0
  407. package/dist/config/define.js.map +1 -0
  408. package/dist/config/index.d.ts +31 -0
  409. package/dist/config/index.d.ts.map +1 -0
  410. package/dist/config/index.js +196 -0
  411. package/dist/config/index.js.map +1 -0
  412. package/dist/config/runtime.d.ts +107 -0
  413. package/dist/config/runtime.d.ts.map +1 -0
  414. package/dist/config/runtime.js +77 -0
  415. package/dist/config/runtime.js.map +1 -0
  416. package/dist/config/types.d.ts +924 -0
  417. package/dist/config/types.d.ts.map +1 -0
  418. package/dist/config/types.js +2 -0
  419. package/dist/config/types.js.map +1 -0
  420. package/dist/content/ai-api.d.ts +21 -0
  421. package/dist/content/ai-api.d.ts.map +1 -0
  422. package/dist/content/ai-api.js +25 -0
  423. package/dist/content/ai-api.js.map +1 -0
  424. package/dist/content/content-graph.d.ts +25 -0
  425. package/dist/content/content-graph.d.ts.map +1 -0
  426. package/dist/content/content-graph.js +40 -0
  427. package/dist/content/content-graph.js.map +1 -0
  428. package/dist/content/extract.d.ts +7 -0
  429. package/dist/content/extract.d.ts.map +1 -0
  430. package/dist/content/extract.js +33 -0
  431. package/dist/content/extract.js.map +1 -0
  432. package/dist/content/index.d.ts +9 -0
  433. package/dist/content/index.d.ts.map +1 -0
  434. package/dist/content/index.js +6 -0
  435. package/dist/content/index.js.map +1 -0
  436. package/dist/content/slug.d.ts +40 -0
  437. package/dist/content/slug.d.ts.map +1 -0
  438. package/dist/content/slug.js +78 -0
  439. package/dist/content/slug.js.map +1 -0
  440. package/dist/content/structured-data.d.ts +163 -0
  441. package/dist/content/structured-data.d.ts.map +1 -0
  442. package/dist/content/structured-data.js +479 -0
  443. package/dist/content/structured-data.js.map +1 -0
  444. package/dist/content-health/cron.d.ts +68 -0
  445. package/dist/content-health/cron.d.ts.map +1 -0
  446. package/dist/content-health/cron.js +167 -0
  447. package/dist/content-health/cron.js.map +1 -0
  448. package/dist/content-health/scanner.d.ts +119 -0
  449. package/dist/content-health/scanner.d.ts.map +1 -0
  450. package/dist/content-health/scanner.js +257 -0
  451. package/dist/content-health/scanner.js.map +1 -0
  452. package/dist/cron/index.d.ts +90 -0
  453. package/dist/cron/index.d.ts.map +1 -0
  454. package/dist/cron/index.js +299 -0
  455. package/dist/cron/index.js.map +1 -0
  456. package/dist/db/adapters/mysql.d.ts +5 -0
  457. package/dist/db/adapters/mysql.d.ts.map +1 -0
  458. package/dist/db/adapters/mysql.js +26 -0
  459. package/dist/db/adapters/mysql.js.map +1 -0
  460. package/dist/db/adapters/postgres.d.ts +7 -0
  461. package/dist/db/adapters/postgres.d.ts.map +1 -0
  462. package/dist/db/adapters/postgres.js +25 -0
  463. package/dist/db/adapters/postgres.js.map +1 -0
  464. package/dist/db/adapters/sqlite.d.ts +5 -0
  465. package/dist/db/adapters/sqlite.d.ts.map +1 -0
  466. package/dist/db/adapters/sqlite.js +27 -0
  467. package/dist/db/adapters/sqlite.js.map +1 -0
  468. package/dist/db/client-types.d.ts +75 -0
  469. package/dist/db/client-types.d.ts.map +1 -0
  470. package/dist/db/client-types.js +2 -0
  471. package/dist/db/client-types.js.map +1 -0
  472. package/dist/db/create-adapter.d.ts +11 -0
  473. package/dist/db/create-adapter.d.ts.map +1 -0
  474. package/dist/db/create-adapter.js +43 -0
  475. package/dist/db/create-adapter.js.map +1 -0
  476. package/dist/db/find-in-batches.d.ts +12 -0
  477. package/dist/db/find-in-batches.d.ts.map +1 -0
  478. package/dist/db/find-in-batches.js +20 -0
  479. package/dist/db/find-in-batches.js.map +1 -0
  480. package/dist/db/index.d.ts +9 -0
  481. package/dist/db/index.d.ts.map +1 -0
  482. package/dist/db/index.js +5 -0
  483. package/dist/db/index.js.map +1 -0
  484. package/dist/db/model-types.d.ts +602 -0
  485. package/dist/db/model-types.d.ts.map +1 -0
  486. package/dist/db/model-types.js +14 -0
  487. package/dist/db/model-types.js.map +1 -0
  488. package/dist/db.d.ts +20 -0
  489. package/dist/db.d.ts.map +1 -0
  490. package/dist/db.js +35 -0
  491. package/dist/db.js.map +1 -0
  492. package/dist/diagnostics/api-metrics.d.ts +135 -0
  493. package/dist/diagnostics/api-metrics.d.ts.map +1 -0
  494. package/dist/diagnostics/api-metrics.js +376 -0
  495. package/dist/diagnostics/api-metrics.js.map +1 -0
  496. package/dist/diagnostics/env.d.ts +44 -0
  497. package/dist/diagnostics/env.d.ts.map +1 -0
  498. package/dist/diagnostics/env.js +354 -0
  499. package/dist/diagnostics/env.js.map +1 -0
  500. package/dist/diagnostics/logger.d.ts +38 -0
  501. package/dist/diagnostics/logger.d.ts.map +1 -0
  502. package/dist/diagnostics/logger.js +89 -0
  503. package/dist/diagnostics/logger.js.map +1 -0
  504. package/dist/diagnostics/sentry.d.ts +8 -0
  505. package/dist/diagnostics/sentry.d.ts.map +1 -0
  506. package/dist/diagnostics/sentry.js +54 -0
  507. package/dist/diagnostics/sentry.js.map +1 -0
  508. package/dist/email/resolve.d.ts +27 -0
  509. package/dist/email/resolve.d.ts.map +1 -0
  510. package/dist/email/resolve.js +68 -0
  511. package/dist/email/resolve.js.map +1 -0
  512. package/dist/email/sender.d.ts +71 -0
  513. package/dist/email/sender.d.ts.map +1 -0
  514. package/dist/email/sender.js +41 -0
  515. package/dist/email/sender.js.map +1 -0
  516. package/dist/email/settings-store.d.ts +116 -0
  517. package/dist/email/settings-store.d.ts.map +1 -0
  518. package/dist/email/settings-store.js +222 -0
  519. package/dist/email/settings-store.js.map +1 -0
  520. package/dist/fields/component-block.d.ts +23 -0
  521. package/dist/fields/component-block.d.ts.map +1 -0
  522. package/dist/fields/component-block.js +137 -0
  523. package/dist/fields/component-block.js.map +1 -0
  524. package/dist/fields/index.d.ts +19 -0
  525. package/dist/fields/index.d.ts.map +1 -0
  526. package/dist/fields/index.js +95 -0
  527. package/dist/fields/index.js.map +1 -0
  528. package/dist/fields/presets.d.ts +144 -0
  529. package/dist/fields/presets.d.ts.map +1 -0
  530. package/dist/fields/presets.js +350 -0
  531. package/dist/fields/presets.js.map +1 -0
  532. package/dist/fields/relations.d.ts +87 -0
  533. package/dist/fields/relations.d.ts.map +1 -0
  534. package/dist/fields/relations.js +231 -0
  535. package/dist/fields/relations.js.map +1 -0
  536. package/dist/forms/analytics.d.ts +62 -0
  537. package/dist/forms/analytics.d.ts.map +1 -0
  538. package/dist/forms/analytics.js +95 -0
  539. package/dist/forms/analytics.js.map +1 -0
  540. package/dist/forms/attribution.d.ts +175 -0
  541. package/dist/forms/attribution.d.ts.map +1 -0
  542. package/dist/forms/attribution.js +577 -0
  543. package/dist/forms/attribution.js.map +1 -0
  544. package/dist/forms/client-validation.d.ts +50 -0
  545. package/dist/forms/client-validation.d.ts.map +1 -0
  546. package/dist/forms/client-validation.js +215 -0
  547. package/dist/forms/client-validation.js.map +1 -0
  548. package/dist/forms/delivery.d.ts +89 -0
  549. package/dist/forms/delivery.d.ts.map +1 -0
  550. package/dist/forms/delivery.js +477 -0
  551. package/dist/forms/delivery.js.map +1 -0
  552. package/dist/forms/encryption.d.ts +20 -0
  553. package/dist/forms/encryption.d.ts.map +1 -0
  554. package/dist/forms/encryption.js +80 -0
  555. package/dist/forms/encryption.js.map +1 -0
  556. package/dist/forms/entries.d.ts +68 -0
  557. package/dist/forms/entries.d.ts.map +1 -0
  558. package/dist/forms/entries.js +557 -0
  559. package/dist/forms/entries.js.map +1 -0
  560. package/dist/forms/files.d.ts +38 -0
  561. package/dist/forms/files.d.ts.map +1 -0
  562. package/dist/forms/files.js +134 -0
  563. package/dist/forms/files.js.map +1 -0
  564. package/dist/forms/index.d.ts +21 -0
  565. package/dist/forms/index.d.ts.map +1 -0
  566. package/dist/forms/index.js +20 -0
  567. package/dist/forms/index.js.map +1 -0
  568. package/dist/forms/notify.d.ts +80 -0
  569. package/dist/forms/notify.d.ts.map +1 -0
  570. package/dist/forms/notify.js +357 -0
  571. package/dist/forms/notify.js.map +1 -0
  572. package/dist/forms/prefetch.d.ts +17 -0
  573. package/dist/forms/prefetch.d.ts.map +1 -0
  574. package/dist/forms/prefetch.js +36 -0
  575. package/dist/forms/prefetch.js.map +1 -0
  576. package/dist/forms/public-html.d.ts +22 -0
  577. package/dist/forms/public-html.d.ts.map +1 -0
  578. package/dist/forms/public-html.js +145 -0
  579. package/dist/forms/public-html.js.map +1 -0
  580. package/dist/forms/service.d.ts +102 -0
  581. package/dist/forms/service.d.ts.map +1 -0
  582. package/dist/forms/service.js +625 -0
  583. package/dist/forms/service.js.map +1 -0
  584. package/dist/forms/spam.d.ts +33 -0
  585. package/dist/forms/spam.d.ts.map +1 -0
  586. package/dist/forms/spam.js +93 -0
  587. package/dist/forms/spam.js.map +1 -0
  588. package/dist/forms/submission.d.ts +132 -0
  589. package/dist/forms/submission.d.ts.map +1 -0
  590. package/dist/forms/submission.js +348 -0
  591. package/dist/forms/submission.js.map +1 -0
  592. package/dist/forms/types.d.ts +259 -0
  593. package/dist/forms/types.d.ts.map +1 -0
  594. package/dist/forms/types.js +20 -0
  595. package/dist/forms/types.js.map +1 -0
  596. package/dist/forms/validation.d.ts +19 -0
  597. package/dist/forms/validation.d.ts.map +1 -0
  598. package/dist/forms/validation.js +166 -0
  599. package/dist/forms/validation.js.map +1 -0
  600. package/dist/forms/webhooks.d.ts +60 -0
  601. package/dist/forms/webhooks.d.ts.map +1 -0
  602. package/dist/forms/webhooks.js +360 -0
  603. package/dist/forms/webhooks.js.map +1 -0
  604. package/dist/forms/webmcp.d.ts +36 -0
  605. package/dist/forms/webmcp.d.ts.map +1 -0
  606. package/dist/forms/webmcp.js +67 -0
  607. package/dist/forms/webmcp.js.map +1 -0
  608. package/dist/forms/xlsx.d.ts +10 -0
  609. package/dist/forms/xlsx.d.ts.map +1 -0
  610. package/dist/forms/xlsx.js +207 -0
  611. package/dist/forms/xlsx.js.map +1 -0
  612. package/dist/generated/browser.d.ts +220 -0
  613. package/dist/generated/browser.js +17 -0
  614. package/dist/generated/client.d.ts +239 -0
  615. package/dist/generated/client.js +34 -0
  616. package/dist/generated/commonInputTypes.d.ts +887 -0
  617. package/dist/generated/commonInputTypes.js +10 -0
  618. package/dist/generated/enums.d.ts +83 -0
  619. package/dist/generated/enums.js +81 -0
  620. package/dist/generated/internal/class.d.ts +517 -0
  621. package/dist/generated/internal/class.js +52 -0
  622. package/dist/generated/internal/prismaNamespace.d.ts +4184 -0
  623. package/dist/generated/internal/prismaNamespace.js +932 -0
  624. package/dist/generated/internal/prismaNamespaceBrowser.d.ts +968 -0
  625. package/dist/generated/internal/prismaNamespaceBrowser.js +903 -0
  626. package/dist/generated/models/AiCrawlerHit.d.ts +1115 -0
  627. package/dist/generated/models/AiCrawlerHit.js +1 -0
  628. package/dist/generated/models/ApiKey.d.ts +1388 -0
  629. package/dist/generated/models/ApiKey.js +1 -0
  630. package/dist/generated/models/ApiRequestMetric.d.ts +1229 -0
  631. package/dist/generated/models/ApiRequestMetric.js +1 -0
  632. package/dist/generated/models/AuditLog.d.ts +1062 -0
  633. package/dist/generated/models/AuditLog.js +1 -0
  634. package/dist/generated/models/BackupRecord.d.ts +1100 -0
  635. package/dist/generated/models/BackupRecord.js +1 -0
  636. package/dist/generated/models/ContentIssue.d.ts +1318 -0
  637. package/dist/generated/models/ContentIssue.js +1 -0
  638. package/dist/generated/models/ContentLock.d.ts +1295 -0
  639. package/dist/generated/models/ContentLock.js +1 -0
  640. package/dist/generated/models/ContentTemplate.d.ts +1254 -0
  641. package/dist/generated/models/ContentTemplate.js +1 -0
  642. package/dist/generated/models/Document.d.ts +3443 -0
  643. package/dist/generated/models/Document.js +1 -0
  644. package/dist/generated/models/Folder.d.ts +1689 -0
  645. package/dist/generated/models/Folder.js +1 -0
  646. package/dist/generated/models/FormDeliveryAttempt.d.ts +1705 -0
  647. package/dist/generated/models/FormDeliveryAttempt.js +1 -0
  648. package/dist/generated/models/FormSchemaVersion.d.ts +1105 -0
  649. package/dist/generated/models/FormSchemaVersion.js +1 -0
  650. package/dist/generated/models/FormSubmission.d.ts +2125 -0
  651. package/dist/generated/models/FormSubmission.js +1 -0
  652. package/dist/generated/models/FormSubmissionFile.d.ts +1438 -0
  653. package/dist/generated/models/FormSubmissionFile.js +1 -0
  654. package/dist/generated/models/FormWebhook.d.ts +1271 -0
  655. package/dist/generated/models/FormWebhook.js +1 -0
  656. package/dist/generated/models/InAppNotification.d.ts +1295 -0
  657. package/dist/generated/models/InAppNotification.js +1 -0
  658. package/dist/generated/models/Invite.d.ts +1240 -0
  659. package/dist/generated/models/Invite.js +1 -0
  660. package/dist/generated/models/Media.d.ts +2759 -0
  661. package/dist/generated/models/Media.js +1 -0
  662. package/dist/generated/models/MediaUsage.d.ts +1301 -0
  663. package/dist/generated/models/MediaUsage.js +1 -0
  664. package/dist/generated/models/OAuthAccount.d.ts +1300 -0
  665. package/dist/generated/models/OAuthAccount.js +1 -0
  666. package/dist/generated/models/PageTemplate.d.ts +1118 -0
  667. package/dist/generated/models/PageTemplate.js +1 -0
  668. package/dist/generated/models/PasswordResetToken.d.ts +1225 -0
  669. package/dist/generated/models/PasswordResetToken.js +1 -0
  670. package/dist/generated/models/Redirect.d.ts +1342 -0
  671. package/dist/generated/models/Redirect.js +1 -0
  672. package/dist/generated/models/Redirect404Hit.d.ts +1107 -0
  673. package/dist/generated/models/Redirect404Hit.js +1 -0
  674. package/dist/generated/models/RedirectSuggestion.d.ts +1185 -0
  675. package/dist/generated/models/RedirectSuggestion.js +1 -0
  676. package/dist/generated/models/SavedSection.d.ts +1156 -0
  677. package/dist/generated/models/SavedSection.js +1 -0
  678. package/dist/generated/models/ScriptTag.d.ts +1291 -0
  679. package/dist/generated/models/ScriptTag.js +1 -0
  680. package/dist/generated/models/SeoAuditRun.d.ts +1570 -0
  681. package/dist/generated/models/SeoAuditRun.js +1 -0
  682. package/dist/generated/models/SeoIssue.d.ts +1873 -0
  683. package/dist/generated/models/SeoIssue.js +1 -0
  684. package/dist/generated/models/Session.d.ts +1330 -0
  685. package/dist/generated/models/Session.js +1 -0
  686. package/dist/generated/models/Site.d.ts +1062 -0
  687. package/dist/generated/models/Site.js +1 -0
  688. package/dist/generated/models/User.d.ts +4344 -0
  689. package/dist/generated/models/User.js +1 -0
  690. package/dist/generated/models/Version.d.ts +1334 -0
  691. package/dist/generated/models/Version.js +1 -0
  692. package/dist/generated/models/WebhookDeliveryLog.d.ts +1479 -0
  693. package/dist/generated/models/WebhookDeliveryLog.js +1 -0
  694. package/dist/generated/models/WebhookEndpoint.d.ts +1331 -0
  695. package/dist/generated/models/WebhookEndpoint.js +1 -0
  696. package/dist/generated/models/WorkflowState.d.ts +1436 -0
  697. package/dist/generated/models/WorkflowState.js +1 -0
  698. package/dist/generated/models.d.ts +37 -0
  699. package/dist/generated/models.js +1 -0
  700. package/dist/graphql/index.d.ts +11 -0
  701. package/dist/graphql/index.d.ts.map +1 -0
  702. package/dist/graphql/index.js +74 -0
  703. package/dist/graphql/index.js.map +1 -0
  704. package/dist/graphql/resolvers.d.ts +8 -0
  705. package/dist/graphql/resolvers.d.ts.map +1 -0
  706. package/dist/graphql/resolvers.js +89 -0
  707. package/dist/graphql/resolvers.js.map +1 -0
  708. package/dist/graphql/schema-builder.d.ts +3 -0
  709. package/dist/graphql/schema-builder.d.ts.map +1 -0
  710. package/dist/graphql/schema-builder.js +103 -0
  711. package/dist/graphql/schema-builder.js.map +1 -0
  712. package/dist/health/index.d.ts +27 -0
  713. package/dist/health/index.d.ts.map +1 -0
  714. package/dist/health/index.js +43 -0
  715. package/dist/health/index.js.map +1 -0
  716. package/dist/i18n/index.d.ts +22 -0
  717. package/dist/i18n/index.d.ts.map +1 -0
  718. package/dist/i18n/index.js +37 -0
  719. package/dist/i18n/index.js.map +1 -0
  720. package/dist/index.d.ts +125 -0
  721. package/dist/index.d.ts.map +1 -0
  722. package/dist/index.js +132 -0
  723. package/dist/index.js.map +1 -0
  724. package/dist/media/content-hash.d.ts +3 -0
  725. package/dist/media/content-hash.d.ts.map +1 -0
  726. package/dist/media/content-hash.js +11 -0
  727. package/dist/media/content-hash.js.map +1 -0
  728. package/dist/media/denormalize.d.ts +23 -0
  729. package/dist/media/denormalize.d.ts.map +1 -0
  730. package/dist/media/denormalize.js +170 -0
  731. package/dist/media/denormalize.js.map +1 -0
  732. package/dist/media/index.d.ts +8 -0
  733. package/dist/media/index.d.ts.map +1 -0
  734. package/dist/media/index.js +5 -0
  735. package/dist/media/index.js.map +1 -0
  736. package/dist/media/merge-document-media.d.ts +23 -0
  737. package/dist/media/merge-document-media.d.ts.map +1 -0
  738. package/dist/media/merge-document-media.js +146 -0
  739. package/dist/media/merge-document-media.js.map +1 -0
  740. package/dist/media/metadata-patch.d.ts +21 -0
  741. package/dist/media/metadata-patch.d.ts.map +1 -0
  742. package/dist/media/metadata-patch.js +37 -0
  743. package/dist/media/metadata-patch.js.map +1 -0
  744. package/dist/media/optimize.d.ts +61 -0
  745. package/dist/media/optimize.d.ts.map +1 -0
  746. package/dist/media/optimize.js +168 -0
  747. package/dist/media/optimize.js.map +1 -0
  748. package/dist/media/seo.d.ts +110 -0
  749. package/dist/media/seo.d.ts.map +1 -0
  750. package/dist/media/seo.js +263 -0
  751. package/dist/media/seo.js.map +1 -0
  752. package/dist/media/usage-sync.d.ts +37 -0
  753. package/dist/media/usage-sync.d.ts.map +1 -0
  754. package/dist/media/usage-sync.js +234 -0
  755. package/dist/media/usage-sync.js.map +1 -0
  756. package/dist/middleware.d.ts +17 -0
  757. package/dist/middleware.d.ts.map +1 -0
  758. package/dist/middleware.js +159 -0
  759. package/dist/middleware.js.map +1 -0
  760. package/dist/multisite/index.d.ts +20 -0
  761. package/dist/multisite/index.d.ts.map +1 -0
  762. package/dist/multisite/index.js +26 -0
  763. package/dist/multisite/index.js.map +1 -0
  764. package/dist/navigation/unresolved-targets.d.ts +35 -0
  765. package/dist/navigation/unresolved-targets.d.ts.map +1 -0
  766. package/dist/navigation/unresolved-targets.js +109 -0
  767. package/dist/navigation/unresolved-targets.js.map +1 -0
  768. package/dist/next/preview.d.ts +10 -0
  769. package/dist/next/preview.d.ts.map +1 -0
  770. package/dist/next/preview.js +17 -0
  771. package/dist/next/preview.js.map +1 -0
  772. package/dist/next/script-tags.d.ts +15 -0
  773. package/dist/next/script-tags.d.ts.map +1 -0
  774. package/dist/next/script-tags.js +58 -0
  775. package/dist/next/script-tags.js.map +1 -0
  776. package/dist/next-site.d.ts +29 -0
  777. package/dist/next-site.d.ts.map +1 -0
  778. package/dist/next-site.js +60 -0
  779. package/dist/next-site.js.map +1 -0
  780. package/dist/next.d.ts +33 -0
  781. package/dist/next.d.ts.map +1 -0
  782. package/dist/next.js +142 -0
  783. package/dist/next.js.map +1 -0
  784. package/dist/notifications/index.d.ts +20 -0
  785. package/dist/notifications/index.d.ts.map +1 -0
  786. package/dist/notifications/index.js +22 -0
  787. package/dist/notifications/index.js.map +1 -0
  788. package/dist/page-builder/a11y-fix.d.ts +20 -0
  789. package/dist/page-builder/a11y-fix.d.ts.map +1 -0
  790. package/dist/page-builder/a11y-fix.js +182 -0
  791. package/dist/page-builder/a11y-fix.js.map +1 -0
  792. package/dist/page-builder/ai-pipeline.d.ts +43 -0
  793. package/dist/page-builder/ai-pipeline.d.ts.map +1 -0
  794. package/dist/page-builder/ai-pipeline.js +165 -0
  795. package/dist/page-builder/ai-pipeline.js.map +1 -0
  796. package/dist/page-builder/blocks.d.ts +27 -0
  797. package/dist/page-builder/blocks.d.ts.map +1 -0
  798. package/dist/page-builder/blocks.js +313 -0
  799. package/dist/page-builder/blocks.js.map +1 -0
  800. package/dist/page-builder/design-scorer.d.ts +27 -0
  801. package/dist/page-builder/design-scorer.d.ts.map +1 -0
  802. package/dist/page-builder/design-scorer.js +612 -0
  803. package/dist/page-builder/design-scorer.js.map +1 -0
  804. package/dist/page-builder/index.d.ts +18 -0
  805. package/dist/page-builder/index.d.ts.map +1 -0
  806. package/dist/page-builder/index.js +20 -0
  807. package/dist/page-builder/index.js.map +1 -0
  808. package/dist/page-builder/schema.d.ts +107 -0
  809. package/dist/page-builder/schema.d.ts.map +1 -0
  810. package/dist/page-builder/schema.js +90 -0
  811. package/dist/page-builder/schema.js.map +1 -0
  812. package/dist/page-builder/seo-analyzer.d.ts +61 -0
  813. package/dist/page-builder/seo-analyzer.d.ts.map +1 -0
  814. package/dist/page-builder/seo-analyzer.js +778 -0
  815. package/dist/page-builder/seo-analyzer.js.map +1 -0
  816. package/dist/page-builder/templates.d.ts +9 -0
  817. package/dist/page-builder/templates.d.ts.map +1 -0
  818. package/dist/page-builder/templates.js +742 -0
  819. package/dist/page-builder/templates.js.map +1 -0
  820. package/dist/page-builder/tree.d.ts +17 -0
  821. package/dist/page-builder/tree.d.ts.map +1 -0
  822. package/dist/page-builder/tree.js +160 -0
  823. package/dist/page-builder/tree.js.map +1 -0
  824. package/dist/page-builder/types.d.ts +112 -0
  825. package/dist/page-builder/types.d.ts.map +1 -0
  826. package/dist/page-builder/types.js +4 -0
  827. package/dist/page-builder/types.js.map +1 -0
  828. package/dist/page-builder/validate.d.ts +6 -0
  829. package/dist/page-builder/validate.d.ts.map +1 -0
  830. package/dist/page-builder/validate.js +87 -0
  831. package/dist/page-builder/validate.js.map +1 -0
  832. package/dist/plan/features.d.ts +17 -0
  833. package/dist/plan/features.d.ts.map +1 -0
  834. package/dist/plan/features.js +73 -0
  835. package/dist/plan/features.js.map +1 -0
  836. package/dist/posts/query.d.ts +50 -0
  837. package/dist/posts/query.d.ts.map +1 -0
  838. package/dist/posts/query.js +105 -0
  839. package/dist/posts/query.js.map +1 -0
  840. package/dist/presence/index.d.ts +24 -0
  841. package/dist/presence/index.d.ts.map +1 -0
  842. package/dist/presence/index.js +99 -0
  843. package/dist/presence/index.js.map +1 -0
  844. package/dist/preview/event-bus.d.ts +39 -0
  845. package/dist/preview/event-bus.d.ts.map +1 -0
  846. package/dist/preview/event-bus.js +73 -0
  847. package/dist/preview/event-bus.js.map +1 -0
  848. package/dist/preview/index.d.ts +36 -0
  849. package/dist/preview/index.d.ts.map +1 -0
  850. package/dist/preview/index.js +68 -0
  851. package/dist/preview/index.js.map +1 -0
  852. package/dist/preview/sse-stream.d.ts +47 -0
  853. package/dist/preview/sse-stream.d.ts.map +1 -0
  854. package/dist/preview/sse-stream.js +111 -0
  855. package/dist/preview/sse-stream.js.map +1 -0
  856. package/dist/privacy/index.d.ts +33 -0
  857. package/dist/privacy/index.d.ts.map +1 -0
  858. package/dist/privacy/index.js +15 -0
  859. package/dist/privacy/index.js.map +1 -0
  860. package/dist/public-redirects.d.ts +78 -0
  861. package/dist/public-redirects.d.ts.map +1 -0
  862. package/dist/public-redirects.js +187 -0
  863. package/dist/public-redirects.js.map +1 -0
  864. package/dist/public-security-headers.d.ts +27 -0
  865. package/dist/public-security-headers.d.ts.map +1 -0
  866. package/dist/public-security-headers.js +40 -0
  867. package/dist/public-security-headers.js.map +1 -0
  868. package/dist/publishing/publish-sync.d.ts +50 -0
  869. package/dist/publishing/publish-sync.d.ts.map +1 -0
  870. package/dist/publishing/publish-sync.js +124 -0
  871. package/dist/publishing/publish-sync.js.map +1 -0
  872. package/dist/purge/adapters.d.ts +60 -0
  873. package/dist/purge/adapters.d.ts.map +1 -0
  874. package/dist/purge/adapters.js +81 -0
  875. package/dist/purge/adapters.js.map +1 -0
  876. package/dist/purge/index.d.ts +12 -0
  877. package/dist/purge/index.d.ts.map +1 -0
  878. package/dist/purge/index.js +10 -0
  879. package/dist/purge/index.js.map +1 -0
  880. package/dist/purge/receiver.d.ts +95 -0
  881. package/dist/purge/receiver.d.ts.map +1 -0
  882. package/dist/purge/receiver.js +176 -0
  883. package/dist/purge/receiver.js.map +1 -0
  884. package/dist/realtime/comments.d.ts +217 -0
  885. package/dist/realtime/comments.d.ts.map +1 -0
  886. package/dist/realtime/comments.js +282 -0
  887. package/dist/realtime/comments.js.map +1 -0
  888. package/dist/realtime/gateway.d.ts +107 -0
  889. package/dist/realtime/gateway.d.ts.map +1 -0
  890. package/dist/realtime/gateway.js +215 -0
  891. package/dist/realtime/gateway.js.map +1 -0
  892. package/dist/realtime/index.d.ts +21 -0
  893. package/dist/realtime/index.d.ts.map +1 -0
  894. package/dist/realtime/index.js +27 -0
  895. package/dist/realtime/index.js.map +1 -0
  896. package/dist/realtime/notification-bus.d.ts +60 -0
  897. package/dist/realtime/notification-bus.d.ts.map +1 -0
  898. package/dist/realtime/notification-bus.js +77 -0
  899. package/dist/realtime/notification-bus.js.map +1 -0
  900. package/dist/realtime/notification-stream.d.ts +50 -0
  901. package/dist/realtime/notification-stream.d.ts.map +1 -0
  902. package/dist/realtime/notification-stream.js +148 -0
  903. package/dist/realtime/notification-stream.js.map +1 -0
  904. package/dist/realtime/notifications.d.ts +201 -0
  905. package/dist/realtime/notifications.d.ts.map +1 -0
  906. package/dist/realtime/notifications.js +233 -0
  907. package/dist/realtime/notifications.js.map +1 -0
  908. package/dist/realtime/persistence.d.ts +72 -0
  909. package/dist/realtime/persistence.d.ts.map +1 -0
  910. package/dist/realtime/persistence.js +53 -0
  911. package/dist/realtime/persistence.js.map +1 -0
  912. package/dist/realtime/sse.d.ts +20 -0
  913. package/dist/realtime/sse.d.ts.map +1 -0
  914. package/dist/realtime/sse.js +31 -0
  915. package/dist/realtime/sse.js.map +1 -0
  916. package/dist/redirects/auto.d.ts +45 -0
  917. package/dist/redirects/auto.d.ts.map +1 -0
  918. package/dist/redirects/auto.js +60 -0
  919. package/dist/redirects/auto.js.map +1 -0
  920. package/dist/redirects/fix-link.d.ts +15 -0
  921. package/dist/redirects/fix-link.d.ts.map +1 -0
  922. package/dist/redirects/fix-link.js +66 -0
  923. package/dist/redirects/fix-link.js.map +1 -0
  924. package/dist/redirects/graph.d.ts +92 -0
  925. package/dist/redirects/graph.d.ts.map +1 -0
  926. package/dist/redirects/graph.js +176 -0
  927. package/dist/redirects/graph.js.map +1 -0
  928. package/dist/redirects/index.d.ts +17 -0
  929. package/dist/redirects/index.d.ts.map +1 -0
  930. package/dist/redirects/index.js +10 -0
  931. package/dist/redirects/index.js.map +1 -0
  932. package/dist/redirects/legitimacy.d.ts +23 -0
  933. package/dist/redirects/legitimacy.d.ts.map +1 -0
  934. package/dist/redirects/legitimacy.js +64 -0
  935. package/dist/redirects/legitimacy.js.map +1 -0
  936. package/dist/redirects/recovery.d.ts +92 -0
  937. package/dist/redirects/recovery.d.ts.map +1 -0
  938. package/dist/redirects/recovery.js +210 -0
  939. package/dist/redirects/recovery.js.map +1 -0
  940. package/dist/redirects/rerank.d.ts +24 -0
  941. package/dist/redirects/rerank.d.ts.map +1 -0
  942. package/dist/redirects/rerank.js +82 -0
  943. package/dist/redirects/rerank.js.map +1 -0
  944. package/dist/redirects/suggest.d.ts +23 -0
  945. package/dist/redirects/suggest.d.ts.map +1 -0
  946. package/dist/redirects/suggest.js +80 -0
  947. package/dist/redirects/suggest.js.map +1 -0
  948. package/dist/redirects/typo.d.ts +10 -0
  949. package/dist/redirects/typo.d.ts.map +1 -0
  950. package/dist/redirects/typo.js +51 -0
  951. package/dist/redirects/typo.js.map +1 -0
  952. package/dist/redirects/validate-destination.d.ts +13 -0
  953. package/dist/redirects/validate-destination.d.ts.map +1 -0
  954. package/dist/redirects/validate-destination.js +51 -0
  955. package/dist/redirects/validate-destination.js.map +1 -0
  956. package/dist/relationships/index.d.ts +13 -0
  957. package/dist/relationships/index.d.ts.map +1 -0
  958. package/dist/relationships/index.js +12 -0
  959. package/dist/relationships/index.js.map +1 -0
  960. package/dist/scheduling/index.d.ts +45 -0
  961. package/dist/scheduling/index.d.ts.map +1 -0
  962. package/dist/scheduling/index.js +141 -0
  963. package/dist/scheduling/index.js.map +1 -0
  964. package/dist/script-tags/index.d.ts +3 -0
  965. package/dist/script-tags/index.d.ts.map +1 -0
  966. package/dist/script-tags/index.js +3 -0
  967. package/dist/script-tags/index.js.map +1 -0
  968. package/dist/script-tags/invalidate.d.ts +3 -0
  969. package/dist/script-tags/invalidate.d.ts.map +1 -0
  970. package/dist/script-tags/invalidate.js +16 -0
  971. package/dist/script-tags/invalidate.js.map +1 -0
  972. package/dist/script-tags/resolve.d.ts +41 -0
  973. package/dist/script-tags/resolve.d.ts.map +1 -0
  974. package/dist/script-tags/resolve.js +130 -0
  975. package/dist/script-tags/resolve.js.map +1 -0
  976. package/dist/search/index.d.ts +25 -0
  977. package/dist/search/index.d.ts.map +1 -0
  978. package/dist/search/index.js +189 -0
  979. package/dist/search/index.js.map +1 -0
  980. package/dist/sections/bridge.d.ts +8 -0
  981. package/dist/sections/bridge.d.ts.map +1 -0
  982. package/dist/sections/bridge.js +211 -0
  983. package/dist/sections/bridge.js.map +1 -0
  984. package/dist/sections/define.d.ts +21 -0
  985. package/dist/sections/define.d.ts.map +1 -0
  986. package/dist/sections/define.js +160 -0
  987. package/dist/sections/define.js.map +1 -0
  988. package/dist/sections/embed.d.ts +24 -0
  989. package/dist/sections/embed.d.ts.map +1 -0
  990. package/dist/sections/embed.js +78 -0
  991. package/dist/sections/embed.js.map +1 -0
  992. package/dist/sections/fields.d.ts +37 -0
  993. package/dist/sections/fields.d.ts.map +1 -0
  994. package/dist/sections/fields.js +50 -0
  995. package/dist/sections/fields.js.map +1 -0
  996. package/dist/sections/helpers.d.ts +149 -0
  997. package/dist/sections/helpers.d.ts.map +1 -0
  998. package/dist/sections/helpers.js +373 -0
  999. package/dist/sections/helpers.js.map +1 -0
  1000. package/dist/sections/index.d.ts +22 -0
  1001. package/dist/sections/index.d.ts.map +1 -0
  1002. package/dist/sections/index.js +18 -0
  1003. package/dist/sections/index.js.map +1 -0
  1004. package/dist/sections/media-enrich.d.ts +45 -0
  1005. package/dist/sections/media-enrich.d.ts.map +1 -0
  1006. package/dist/sections/media-enrich.js +137 -0
  1007. package/dist/sections/media-enrich.js.map +1 -0
  1008. package/dist/sections/migrate.d.ts +42 -0
  1009. package/dist/sections/migrate.d.ts.map +1 -0
  1010. package/dist/sections/migrate.js +66 -0
  1011. package/dist/sections/migrate.js.map +1 -0
  1012. package/dist/sections/registry.d.ts +46 -0
  1013. package/dist/sections/registry.d.ts.map +1 -0
  1014. package/dist/sections/registry.js +598 -0
  1015. package/dist/sections/registry.js.map +1 -0
  1016. package/dist/sections/types.d.ts +192 -0
  1017. package/dist/sections/types.d.ts.map +1 -0
  1018. package/dist/sections/types.js +21 -0
  1019. package/dist/sections/types.js.map +1 -0
  1020. package/dist/sections/validate.d.ts +12 -0
  1021. package/dist/sections/validate.d.ts.map +1 -0
  1022. package/dist/sections/validate.js +186 -0
  1023. package/dist/sections/validate.js.map +1 -0
  1024. package/dist/sections/widget-embed.d.ts +45 -0
  1025. package/dist/sections/widget-embed.d.ts.map +1 -0
  1026. package/dist/sections/widget-embed.js +129 -0
  1027. package/dist/sections/widget-embed.js.map +1 -0
  1028. package/dist/security/access.d.ts +35 -0
  1029. package/dist/security/access.d.ts.map +1 -0
  1030. package/dist/security/access.js +133 -0
  1031. package/dist/security/access.js.map +1 -0
  1032. package/dist/security/anomaly-detection.d.ts +17 -0
  1033. package/dist/security/anomaly-detection.d.ts.map +1 -0
  1034. package/dist/security/anomaly-detection.js +39 -0
  1035. package/dist/security/anomaly-detection.js.map +1 -0
  1036. package/dist/security/api-key-enhanced.d.ts +68 -0
  1037. package/dist/security/api-key-enhanced.d.ts.map +1 -0
  1038. package/dist/security/api-key-enhanced.js +76 -0
  1039. package/dist/security/api-key-enhanced.js.map +1 -0
  1040. package/dist/security/audit.d.ts +46 -0
  1041. package/dist/security/audit.d.ts.map +1 -0
  1042. package/dist/security/audit.js +67 -0
  1043. package/dist/security/audit.js.map +1 -0
  1044. package/dist/security/breach-check.d.ts +3 -0
  1045. package/dist/security/breach-check.d.ts.map +1 -0
  1046. package/dist/security/breach-check.js +27 -0
  1047. package/dist/security/breach-check.js.map +1 -0
  1048. package/dist/security/captcha.d.ts +67 -0
  1049. package/dist/security/captcha.d.ts.map +1 -0
  1050. package/dist/security/captcha.js +186 -0
  1051. package/dist/security/captcha.js.map +1 -0
  1052. package/dist/security/center/gather.d.ts +20 -0
  1053. package/dist/security/center/gather.d.ts.map +1 -0
  1054. package/dist/security/center/gather.js +240 -0
  1055. package/dist/security/center/gather.js.map +1 -0
  1056. package/dist/security/center/index.d.ts +13 -0
  1057. package/dist/security/center/index.d.ts.map +1 -0
  1058. package/dist/security/center/index.js +4 -0
  1059. package/dist/security/center/index.js.map +1 -0
  1060. package/dist/security/center/settings.d.ts +48 -0
  1061. package/dist/security/center/settings.d.ts.map +1 -0
  1062. package/dist/security/center/settings.js +218 -0
  1063. package/dist/security/center/settings.js.map +1 -0
  1064. package/dist/security/center/status.d.ts +10 -0
  1065. package/dist/security/center/status.d.ts.map +1 -0
  1066. package/dist/security/center/status.js +249 -0
  1067. package/dist/security/center/status.js.map +1 -0
  1068. package/dist/security/center/summaries.d.ts +21 -0
  1069. package/dist/security/center/summaries.d.ts.map +1 -0
  1070. package/dist/security/center/summaries.js +65 -0
  1071. package/dist/security/center/summaries.js.map +1 -0
  1072. package/dist/security/center/types.d.ts +142 -0
  1073. package/dist/security/center/types.d.ts.map +1 -0
  1074. package/dist/security/center/types.js +12 -0
  1075. package/dist/security/center/types.js.map +1 -0
  1076. package/dist/security/client-ip.d.ts +23 -0
  1077. package/dist/security/client-ip.d.ts.map +1 -0
  1078. package/dist/security/client-ip.js +97 -0
  1079. package/dist/security/client-ip.js.map +1 -0
  1080. package/dist/security/cors.d.ts +11 -0
  1081. package/dist/security/cors.d.ts.map +1 -0
  1082. package/dist/security/cors.js +33 -0
  1083. package/dist/security/cors.js.map +1 -0
  1084. package/dist/security/csp-nonces.d.ts +5 -0
  1085. package/dist/security/csp-nonces.d.ts.map +1 -0
  1086. package/dist/security/csp-nonces.js +24 -0
  1087. package/dist/security/csp-nonces.js.map +1 -0
  1088. package/dist/security/csrf.d.ts +5 -0
  1089. package/dist/security/csrf.d.ts.map +1 -0
  1090. package/dist/security/csrf.js +20 -0
  1091. package/dist/security/csrf.js.map +1 -0
  1092. package/dist/security/encrypted-fields.d.ts +14 -0
  1093. package/dist/security/encrypted-fields.d.ts.map +1 -0
  1094. package/dist/security/encrypted-fields.js +94 -0
  1095. package/dist/security/encrypted-fields.js.map +1 -0
  1096. package/dist/security/headers.d.ts +11 -0
  1097. package/dist/security/headers.d.ts.map +1 -0
  1098. package/dist/security/headers.js +32 -0
  1099. package/dist/security/headers.js.map +1 -0
  1100. package/dist/security/index.d.ts +40 -0
  1101. package/dist/security/index.d.ts.map +1 -0
  1102. package/dist/security/index.js +26 -0
  1103. package/dist/security/index.js.map +1 -0
  1104. package/dist/security/internal-keys.d.ts +15 -0
  1105. package/dist/security/internal-keys.d.ts.map +1 -0
  1106. package/dist/security/internal-keys.js +33 -0
  1107. package/dist/security/internal-keys.js.map +1 -0
  1108. package/dist/security/ip-allowlist.d.ts +15 -0
  1109. package/dist/security/ip-allowlist.d.ts.map +1 -0
  1110. package/dist/security/ip-allowlist.js +141 -0
  1111. package/dist/security/ip-allowlist.js.map +1 -0
  1112. package/dist/security/ip-canon.d.ts +71 -0
  1113. package/dist/security/ip-canon.d.ts.map +1 -0
  1114. package/dist/security/ip-canon.js +352 -0
  1115. package/dist/security/ip-canon.js.map +1 -0
  1116. package/dist/security/middleware.d.ts +20 -0
  1117. package/dist/security/middleware.d.ts.map +1 -0
  1118. package/dist/security/middleware.js +45 -0
  1119. package/dist/security/middleware.js.map +1 -0
  1120. package/dist/security/rate-limit-policy.d.ts +40 -0
  1121. package/dist/security/rate-limit-policy.d.ts.map +1 -0
  1122. package/dist/security/rate-limit-policy.js +57 -0
  1123. package/dist/security/rate-limit-policy.js.map +1 -0
  1124. package/dist/security/rate-limit.d.ts +55 -0
  1125. package/dist/security/rate-limit.d.ts.map +1 -0
  1126. package/dist/security/rate-limit.js +298 -0
  1127. package/dist/security/rate-limit.js.map +1 -0
  1128. package/dist/security/reauth.d.ts +16 -0
  1129. package/dist/security/reauth.d.ts.map +1 -0
  1130. package/dist/security/reauth.js +56 -0
  1131. package/dist/security/reauth.js.map +1 -0
  1132. package/dist/security/redact.d.ts +12 -0
  1133. package/dist/security/redact.d.ts.map +1 -0
  1134. package/dist/security/redact.js +44 -0
  1135. package/dist/security/redact.js.map +1 -0
  1136. package/dist/security/safe-fetch.d.ts +57 -0
  1137. package/dist/security/safe-fetch.d.ts.map +1 -0
  1138. package/dist/security/safe-fetch.js +71 -0
  1139. package/dist/security/safe-fetch.js.map +1 -0
  1140. package/dist/security/sanitize-document.d.ts +14 -0
  1141. package/dist/security/sanitize-document.d.ts.map +1 -0
  1142. package/dist/security/sanitize-document.js +117 -0
  1143. package/dist/security/sanitize-document.js.map +1 -0
  1144. package/dist/security/sanitize.d.ts +13 -0
  1145. package/dist/security/sanitize.d.ts.map +1 -0
  1146. package/dist/security/sanitize.js +64 -0
  1147. package/dist/security/sanitize.js.map +1 -0
  1148. package/dist/security/secret-storage.d.ts +22 -0
  1149. package/dist/security/secret-storage.d.ts.map +1 -0
  1150. package/dist/security/secret-storage.js +75 -0
  1151. package/dist/security/secret-storage.js.map +1 -0
  1152. package/dist/security/security-txt.d.ts +12 -0
  1153. package/dist/security/security-txt.d.ts.map +1 -0
  1154. package/dist/security/security-txt.js +19 -0
  1155. package/dist/security/security-txt.js.map +1 -0
  1156. package/dist/security/session-limits.d.ts +17 -0
  1157. package/dist/security/session-limits.d.ts.map +1 -0
  1158. package/dist/security/session-limits.js +14 -0
  1159. package/dist/security/session-limits.js.map +1 -0
  1160. package/dist/security/upload.d.ts +32 -0
  1161. package/dist/security/upload.d.ts.map +1 -0
  1162. package/dist/security/upload.js +129 -0
  1163. package/dist/security/upload.js.map +1 -0
  1164. package/dist/security/webhook.d.ts +30 -0
  1165. package/dist/security/webhook.d.ts.map +1 -0
  1166. package/dist/security/webhook.js +133 -0
  1167. package/dist/security/webhook.js.map +1 -0
  1168. package/dist/seo/ai-bots.d.ts +56 -0
  1169. package/dist/seo/ai-bots.d.ts.map +1 -0
  1170. package/dist/seo/ai-bots.js +125 -0
  1171. package/dist/seo/ai-bots.js.map +1 -0
  1172. package/dist/seo/ai-crawler-log.d.ts +14 -0
  1173. package/dist/seo/ai-crawler-log.d.ts.map +1 -0
  1174. package/dist/seo/ai-crawler-log.js +48 -0
  1175. package/dist/seo/ai-crawler-log.js.map +1 -0
  1176. package/dist/seo/alt-text.d.ts +39 -0
  1177. package/dist/seo/alt-text.d.ts.map +1 -0
  1178. package/dist/seo/alt-text.js +67 -0
  1179. package/dist/seo/alt-text.js.map +1 -0
  1180. package/dist/seo/analysis.d.ts +75 -0
  1181. package/dist/seo/analysis.d.ts.map +1 -0
  1182. package/dist/seo/analysis.js +641 -0
  1183. package/dist/seo/analysis.js.map +1 -0
  1184. package/dist/seo/audit-engine.d.ts +124 -0
  1185. package/dist/seo/audit-engine.d.ts.map +1 -0
  1186. package/dist/seo/audit-engine.js +534 -0
  1187. package/dist/seo/audit-engine.js.map +1 -0
  1188. package/dist/seo/audit-runner.d.ts +84 -0
  1189. package/dist/seo/audit-runner.d.ts.map +1 -0
  1190. package/dist/seo/audit-runner.js +372 -0
  1191. package/dist/seo/audit-runner.js.map +1 -0
  1192. package/dist/seo/audit-signals.d.ts +28 -0
  1193. package/dist/seo/audit-signals.d.ts.map +1 -0
  1194. package/dist/seo/audit-signals.js +133 -0
  1195. package/dist/seo/audit-signals.js.map +1 -0
  1196. package/dist/seo/config-store.d.ts +99 -0
  1197. package/dist/seo/config-store.d.ts.map +1 -0
  1198. package/dist/seo/config-store.js +194 -0
  1199. package/dist/seo/config-store.js.map +1 -0
  1200. package/dist/seo/confirm-broken-links.d.ts +48 -0
  1201. package/dist/seo/confirm-broken-links.d.ts.map +1 -0
  1202. package/dist/seo/confirm-broken-links.js +135 -0
  1203. package/dist/seo/confirm-broken-links.js.map +1 -0
  1204. package/dist/seo/content-markdown.d.ts +26 -0
  1205. package/dist/seo/content-markdown.d.ts.map +1 -0
  1206. package/dist/seo/content-markdown.js +235 -0
  1207. package/dist/seo/content-markdown.js.map +1 -0
  1208. package/dist/seo/document-content.d.ts +18 -0
  1209. package/dist/seo/document-content.d.ts.map +1 -0
  1210. package/dist/seo/document-content.js +80 -0
  1211. package/dist/seo/document-content.js.map +1 -0
  1212. package/dist/seo/document-path.d.ts +33 -0
  1213. package/dist/seo/document-path.d.ts.map +1 -0
  1214. package/dist/seo/document-path.js +44 -0
  1215. package/dist/seo/document-path.js.map +1 -0
  1216. package/dist/seo/feeds.d.ts +44 -0
  1217. package/dist/seo/feeds.d.ts.map +1 -0
  1218. package/dist/seo/feeds.js +95 -0
  1219. package/dist/seo/feeds.js.map +1 -0
  1220. package/dist/seo/fix-brief-export.d.ts +47 -0
  1221. package/dist/seo/fix-brief-export.d.ts.map +1 -0
  1222. package/dist/seo/fix-brief-export.js +224 -0
  1223. package/dist/seo/fix-brief-export.js.map +1 -0
  1224. package/dist/seo/index-status.d.ts +56 -0
  1225. package/dist/seo/index-status.d.ts.map +1 -0
  1226. package/dist/seo/index-status.js +193 -0
  1227. package/dist/seo/index-status.js.map +1 -0
  1228. package/dist/seo/index.d.ts +68 -0
  1229. package/dist/seo/index.d.ts.map +1 -0
  1230. package/dist/seo/index.js +36 -0
  1231. package/dist/seo/index.js.map +1 -0
  1232. package/dist/seo/issue-batch-briefs.d.ts +37 -0
  1233. package/dist/seo/issue-batch-briefs.d.ts.map +1 -0
  1234. package/dist/seo/issue-batch-briefs.js +85 -0
  1235. package/dist/seo/issue-batch-briefs.js.map +1 -0
  1236. package/dist/seo/issue-content-brief.d.ts +51 -0
  1237. package/dist/seo/issue-content-brief.d.ts.map +1 -0
  1238. package/dist/seo/issue-content-brief.js +267 -0
  1239. package/dist/seo/issue-content-brief.js.map +1 -0
  1240. package/dist/seo/issue-content-research.d.ts +51 -0
  1241. package/dist/seo/issue-content-research.d.ts.map +1 -0
  1242. package/dist/seo/issue-content-research.js +303 -0
  1243. package/dist/seo/issue-content-research.js.map +1 -0
  1244. package/dist/seo/issue-fix-ai.d.ts +39 -0
  1245. package/dist/seo/issue-fix-ai.d.ts.map +1 -0
  1246. package/dist/seo/issue-fix-ai.js +320 -0
  1247. package/dist/seo/issue-fix-ai.js.map +1 -0
  1248. package/dist/seo/issue-fix-redirect.d.ts +18 -0
  1249. package/dist/seo/issue-fix-redirect.d.ts.map +1 -0
  1250. package/dist/seo/issue-fix-redirect.js +153 -0
  1251. package/dist/seo/issue-fix-redirect.js.map +1 -0
  1252. package/dist/seo/issue-fix.d.ts +72 -0
  1253. package/dist/seo/issue-fix.d.ts.map +1 -0
  1254. package/dist/seo/issue-fix.js +266 -0
  1255. package/dist/seo/issue-fix.js.map +1 -0
  1256. package/dist/seo/link-graph.d.ts +54 -0
  1257. package/dist/seo/link-graph.d.ts.map +1 -0
  1258. package/dist/seo/link-graph.js +0 -0
  1259. package/dist/seo/link-graph.js.map +1 -0
  1260. package/dist/seo/link-probe.d.ts +49 -0
  1261. package/dist/seo/link-probe.d.ts.map +1 -0
  1262. package/dist/seo/link-probe.js +147 -0
  1263. package/dist/seo/link-probe.js.map +1 -0
  1264. package/dist/seo/llms-select.d.ts +34 -0
  1265. package/dist/seo/llms-select.d.ts.map +1 -0
  1266. package/dist/seo/llms-select.js +67 -0
  1267. package/dist/seo/llms-select.js.map +1 -0
  1268. package/dist/seo/llms-txt.d.ts +40 -0
  1269. package/dist/seo/llms-txt.d.ts.map +1 -0
  1270. package/dist/seo/llms-txt.js +177 -0
  1271. package/dist/seo/llms-txt.js.map +1 -0
  1272. package/dist/seo/meta-tags.d.ts +108 -0
  1273. package/dist/seo/meta-tags.d.ts.map +1 -0
  1274. package/dist/seo/meta-tags.js +353 -0
  1275. package/dist/seo/meta-tags.js.map +1 -0
  1276. package/dist/seo/migrate-meta.d.ts +23 -0
  1277. package/dist/seo/migrate-meta.d.ts.map +1 -0
  1278. package/dist/seo/migrate-meta.js +114 -0
  1279. package/dist/seo/migrate-meta.js.map +1 -0
  1280. package/dist/seo/migrate-schema.d.ts +28 -0
  1281. package/dist/seo/migrate-schema.d.ts.map +1 -0
  1282. package/dist/seo/migrate-schema.js +119 -0
  1283. package/dist/seo/migrate-schema.js.map +1 -0
  1284. package/dist/seo/page-meta.d.ts +179 -0
  1285. package/dist/seo/page-meta.d.ts.map +1 -0
  1286. package/dist/seo/page-meta.js +710 -0
  1287. package/dist/seo/page-meta.js.map +1 -0
  1288. package/dist/seo/public-site-url.d.ts +16 -0
  1289. package/dist/seo/public-site-url.d.ts.map +1 -0
  1290. package/dist/seo/public-site-url.js +39 -0
  1291. package/dist/seo/public-site-url.js.map +1 -0
  1292. package/dist/seo/resolve-path.d.ts +22 -0
  1293. package/dist/seo/resolve-path.d.ts.map +1 -0
  1294. package/dist/seo/resolve-path.js +53 -0
  1295. package/dist/seo/resolve-path.js.map +1 -0
  1296. package/dist/seo/rewrite-public-origin.d.ts +12 -0
  1297. package/dist/seo/rewrite-public-origin.d.ts.map +1 -0
  1298. package/dist/seo/rewrite-public-origin.js +17 -0
  1299. package/dist/seo/rewrite-public-origin.js.map +1 -0
  1300. package/dist/seo/robots.d.ts +45 -0
  1301. package/dist/seo/robots.d.ts.map +1 -0
  1302. package/dist/seo/robots.js +90 -0
  1303. package/dist/seo/robots.js.map +1 -0
  1304. package/dist/seo/schema-sync.d.ts +65 -0
  1305. package/dist/seo/schema-sync.d.ts.map +1 -0
  1306. package/dist/seo/schema-sync.js +163 -0
  1307. package/dist/seo/schema-sync.js.map +1 -0
  1308. package/dist/seo/score.d.ts +132 -0
  1309. package/dist/seo/score.d.ts.map +1 -0
  1310. package/dist/seo/score.js +216 -0
  1311. package/dist/seo/score.js.map +1 -0
  1312. package/dist/seo/serving-origin.d.ts +42 -0
  1313. package/dist/seo/serving-origin.d.ts.map +1 -0
  1314. package/dist/seo/serving-origin.js +83 -0
  1315. package/dist/seo/serving-origin.js.map +1 -0
  1316. package/dist/seo/site-identity.d.ts +60 -0
  1317. package/dist/seo/site-identity.d.ts.map +1 -0
  1318. package/dist/seo/site-identity.js +109 -0
  1319. package/dist/seo/site-identity.js.map +1 -0
  1320. package/dist/seo/sitemap-notify.d.ts +123 -0
  1321. package/dist/seo/sitemap-notify.d.ts.map +1 -0
  1322. package/dist/seo/sitemap-notify.js +270 -0
  1323. package/dist/seo/sitemap-notify.js.map +1 -0
  1324. package/dist/seo/sitemap-public.d.ts +43 -0
  1325. package/dist/seo/sitemap-public.d.ts.map +1 -0
  1326. package/dist/seo/sitemap-public.js +213 -0
  1327. package/dist/seo/sitemap-public.js.map +1 -0
  1328. package/dist/seo/title-templates.d.ts +80 -0
  1329. package/dist/seo/title-templates.d.ts.map +1 -0
  1330. package/dist/seo/title-templates.js +175 -0
  1331. package/dist/seo/title-templates.js.map +1 -0
  1332. package/dist/server-site.d.ts +55 -0
  1333. package/dist/server-site.d.ts.map +1 -0
  1334. package/dist/server-site.js +184 -0
  1335. package/dist/server-site.js.map +1 -0
  1336. package/dist/setup/index.d.ts +68 -0
  1337. package/dist/setup/index.d.ts.map +1 -0
  1338. package/dist/setup/index.js +153 -0
  1339. package/dist/setup/index.js.map +1 -0
  1340. package/dist/site.d.ts +178 -0
  1341. package/dist/site.d.ts.map +1 -0
  1342. package/dist/site.js +222 -0
  1343. package/dist/site.js.map +1 -0
  1344. package/dist/storage/auto-wire.d.ts +14 -0
  1345. package/dist/storage/auto-wire.d.ts.map +1 -0
  1346. package/dist/storage/auto-wire.js +60 -0
  1347. package/dist/storage/auto-wire.js.map +1 -0
  1348. package/dist/storage/index.d.ts +21 -0
  1349. package/dist/storage/index.d.ts.map +1 -0
  1350. package/dist/storage/index.js +14 -0
  1351. package/dist/storage/index.js.map +1 -0
  1352. package/dist/templates/index.d.ts +16 -0
  1353. package/dist/templates/index.d.ts.map +1 -0
  1354. package/dist/templates/index.js +23 -0
  1355. package/dist/templates/index.js.map +1 -0
  1356. package/dist/upgrade/changelog.d.ts +18 -0
  1357. package/dist/upgrade/changelog.d.ts.map +1 -0
  1358. package/dist/upgrade/changelog.js +60 -0
  1359. package/dist/upgrade/changelog.js.map +1 -0
  1360. package/dist/upgrade/index.d.ts +7 -0
  1361. package/dist/upgrade/index.d.ts.map +1 -0
  1362. package/dist/upgrade/index.js +4 -0
  1363. package/dist/upgrade/index.js.map +1 -0
  1364. package/dist/upgrade/upgrade-pr.d.ts +16 -0
  1365. package/dist/upgrade/upgrade-pr.d.ts.map +1 -0
  1366. package/dist/upgrade/upgrade-pr.js +128 -0
  1367. package/dist/upgrade/upgrade-pr.js.map +1 -0
  1368. package/dist/upgrade/version-check.d.ts +59 -0
  1369. package/dist/upgrade/version-check.d.ts.map +1 -0
  1370. package/dist/upgrade/version-check.js +142 -0
  1371. package/dist/upgrade/version-check.js.map +1 -0
  1372. package/dist/validation/publish.d.ts +53 -0
  1373. package/dist/validation/publish.d.ts.map +1 -0
  1374. package/dist/validation/publish.js +75 -0
  1375. package/dist/validation/publish.js.map +1 -0
  1376. package/dist/webhooks/index.d.ts +99 -0
  1377. package/dist/webhooks/index.d.ts.map +1 -0
  1378. package/dist/webhooks/index.js +387 -0
  1379. package/dist/webhooks/index.js.map +1 -0
  1380. package/dist/webhooks/signing.d.ts +68 -0
  1381. package/dist/webhooks/signing.d.ts.map +1 -0
  1382. package/dist/webhooks/signing.js +98 -0
  1383. package/dist/webhooks/signing.js.map +1 -0
  1384. package/dist/workflow/index.d.ts +8 -0
  1385. package/dist/workflow/index.d.ts.map +1 -0
  1386. package/dist/workflow/index.js +56 -0
  1387. package/dist/workflow/index.js.map +1 -0
  1388. package/dist/workflows/index.d.ts +30 -0
  1389. package/dist/workflows/index.d.ts.map +1 -0
  1390. package/dist/workflows/index.js +14 -0
  1391. package/dist/workflows/index.js.map +1 -0
  1392. package/package.json +250 -0
  1393. package/prisma/migrations/0001_init/migration.sql +941 -0
  1394. package/prisma/migrations/0002_media_usage_field_path/migration.sql +11 -0
  1395. package/prisma/migrations/0003_ai_crawler_hits/migration.sql +21 -0
  1396. package/prisma/migrations/0004_drop_search_vector/migration.sql +4 -0
  1397. package/prisma/migrations/0005_script_tag_delivery_controls/migration.sql +8 -0
  1398. package/prisma/migrations/0006_totp_last_step/migration.sql +4 -0
  1399. package/prisma/migrations/0007_workflow_fk_drop_dead_enums/migration.sql +27 -0
  1400. package/prisma/migrations/0008_form_delivery_attempts/migration.sql +29 -0
  1401. package/prisma/migrations/0009_webhook_secret_rotation/migration.sql +6 -0
  1402. package/prisma/migrations/0010_media_is_decorative/migration.sql +3 -0
  1403. package/prisma/migrations/0011_media_content_hash/migration.sql +4 -0
  1404. package/prisma/migrations/0012_rename_to_prenta/migration.sql +89 -0
  1405. package/prisma/migrations/migration_lock.toml +3 -0
  1406. package/prisma/schema.prisma +995 -0
  1407. package/prisma/seed.ts +82 -0
  1408. package/schema-fragments/cms-schema.prisma +526 -0
@@ -0,0 +1,1366 @@
1
+ import { logEvent } from '../../security/audit.js';
2
+ import { safeFetch, SsrfBlockedError } from '../../security/safe-fetch.js';
3
+ import { extractOutboundUrlsFromDocumentData, isLinkProbeIssueStatus, LINK_PROBE_HEADERS, } from '../../seo/link-probe.js';
4
+ import { getPrentaConfig } from '../../config/runtime.js';
5
+ import { guardedDb } from '../guarded-db.js';
6
+ import { computeLightSeoScore } from './dashboard.js';
7
+ import { resolveDocumentUrl } from '../../seo/page-meta.js';
8
+ import { resolveSeoEnvironment, isDocumentNoIndex, } from '../../seo/robots.js';
9
+ import { buildAiBotRobotsLines } from '../../seo/ai-bots.js';
10
+ import { getSeoOverrides, resolveSeoModuleSettings, } from '../../seo/config-store.js';
11
+ import { collectSectionImageUrls, featuredImageUrl } from '../../sections/index.js';
12
+ import { collectionSitemapPublicUrl, parseCollectionSitemapFilename, resolveCollectionFromSitemapSlug, sitemapBaseName, sitemapStylesheetPi, SITEMAP_INDEX_XSL, SITEMAP_URLSET_XSL, } from '../../seo/sitemap-public.js';
13
+ import { json, errorResponse, internalError, escapeXml, SITEMAP_PAGE_SIZE, renderOgSvg, safeFindMany, requireAuth, WRITE_ROLES, ADMIN_ROLES, requireRole, enforceDocumentReadAccess, } from '../route-helpers.js';
14
+ /**
15
+ * Load the runtime config with DB-stored SEO overrides applied. Used by every
16
+ * public SEO surface (sitemap, robots, og.png) and by /resolve so admin edits
17
+ * in the Settings → SEO panel take effect without a redeploy.
18
+ *
19
+ * Falls back to the static config when no override row exists yet — first
20
+ * boot of a freshly-installed CMS keeps working.
21
+ */
22
+ export async function loadEffectiveConfig() {
23
+ const base = getPrentaConfig();
24
+ if (!base)
25
+ return null;
26
+ try {
27
+ const { getSeoOverrides, applySeoOverrides } = await import('../../seo/config-store.js');
28
+ const overrides = await getSeoOverrides(guardedDb());
29
+ return applySeoOverrides(base, overrides);
30
+ }
31
+ catch {
32
+ return base;
33
+ }
34
+ }
35
+ /**
36
+ * Whether a published document resolves to `noindex` and therefore must be kept
37
+ * OUT of the sitemap. Listing a noindexed URL in the sitemap ("index me") while
38
+ * its page emits a `noindex` meta tag ("don't") sends crawlers conflicting
39
+ * signals and wastes crawl budget — Google explicitly flags this. Mirrors the
40
+ * robots inputs used by `composePageMeta` so the sitemap and the rendered meta
41
+ * tag always agree.
42
+ */
43
+ function sitemapDocumentNoIndex(data, collectionSeo, siteSeo, environment) {
44
+ const pageSettings = (data.pageSettings ?? data._pageSettings ?? {});
45
+ return isDocumentNoIndex({
46
+ pageSettings,
47
+ data,
48
+ collectionSeo,
49
+ siteSeo,
50
+ environment,
51
+ });
52
+ }
53
+ /** Google image-sitemap extension namespace. */
54
+ const SITEMAP_IMAGE_NS = 'http://www.google.com/schemas/sitemap-image/1.1';
55
+ /** Cap image entries per URL — Google honors up to 1,000; we keep it modest. */
56
+ const MAX_IMAGES_PER_URL = 50;
57
+ /**
58
+ * Collect the public image URLs referenced by a document (featured image plus
59
+ * any `feature`/`hero`/`gallery` section images), absolutized against the site
60
+ * origin, deduped, and capped. Used to emit `<image:image>` entries when the
61
+ * "Include images in sitemap" crawl setting is on.
62
+ */
63
+ function collectDocumentImageUrls(data, base) {
64
+ const urls = new Set();
65
+ const add = (u) => {
66
+ if (!u)
67
+ return;
68
+ const abs = u.startsWith('http://') || u.startsWith('https://')
69
+ ? u
70
+ : u.startsWith('/')
71
+ ? `${base}${u}`
72
+ : null;
73
+ if (abs)
74
+ urls.add(abs);
75
+ };
76
+ add(featuredImageUrl(data.featuredImage));
77
+ for (const u of collectSectionImageUrls(data.sections))
78
+ add(u);
79
+ return [...urls].slice(0, MAX_IMAGES_PER_URL);
80
+ }
81
+ export function siteUrlFromRequest(request, cfg) {
82
+ const seo = (cfg ?? getPrentaConfig())?.seo;
83
+ if (seo?.siteUrl)
84
+ return seo.siteUrl.replace(/\/+$/, '');
85
+ // Fall back to the request origin so the routes work on preview deploys
86
+ // before the integrator has configured siteUrl. On production hosts this
87
+ // is a serving-reality leak (absolute URLs become the CMS host) — log loud
88
+ // so Launch Gate E / ops catch it; still return a value so SEO routes do
89
+ // not 500 an entire site that forgot the env.
90
+ const isProd = process.env.NODE_ENV === 'production' ||
91
+ process.env.VERCEL_ENV === 'production' ||
92
+ process.env.VERCEL_ENV === 'preview';
93
+ try {
94
+ const u = new URL(request.url);
95
+ const fallback = `${u.protocol}//${u.host}`;
96
+ if (isProd && typeof console !== 'undefined') {
97
+ console.error('[prenta] seo.siteUrl / NEXT_PUBLIC_SITE_URL is unset; ' +
98
+ `falling back to request origin (${fallback}). Set the public apex ` +
99
+ 'or absolute URLs in sitemap/robots/feeds will point at the wrong host.');
100
+ }
101
+ return fallback;
102
+ }
103
+ catch {
104
+ return '';
105
+ }
106
+ }
107
+ export function registerSeoPublicRoutes(router) {
108
+ const db = guardedDb;
109
+ // ---------------------------------------------------------------------------
110
+ // Public SEO surfaces: sitemap.xml, per-collection sitemaps, robots.txt,
111
+ // and the dynamic /og.png OG-image endpoint. These are unauthenticated by
112
+ // design — search engines and social crawlers will fetch them.
113
+ // ---------------------------------------------------------------------------
114
+ function sitemapEligibleCollections(cfg, opts) {
115
+ const resolved = cfg ?? getPrentaConfig();
116
+ if (!resolved)
117
+ return [];
118
+ const includePosts = opts?.includePosts ?? true;
119
+ const excluded = new Set(resolved.seo?.sitemap?.excludeCollections ?? []);
120
+ const out = [];
121
+ for (const [slug, col] of Object.entries(resolved.collections ?? {})) {
122
+ // Only publicly-rendered content types belong in the sitemap. Structural
123
+ // / utility collections (navigation menus, footers, tags, templates) have
124
+ // no `type` and must never produce indexable sitemap URLs.
125
+ if (col.type !== 'page' && col.type !== 'post')
126
+ continue;
127
+ // Honor the "Include posts in sitemap" crawl setting (Settings → SEO →
128
+ // Technical). When off, post-type collections are dropped entirely.
129
+ if (col.type === 'post' && !includePosts)
130
+ continue;
131
+ if (col.admin?.hidden)
132
+ continue;
133
+ if (excluded.has(slug))
134
+ continue;
135
+ if (col.seo?.excludeFromSitemap)
136
+ continue;
137
+ out.push({ slug, urlPrefix: col.urlPrefix, type: col.type, seo: col.seo });
138
+ }
139
+ return out;
140
+ }
141
+ router.get('/sitemap.xml', async (request) => {
142
+ try {
143
+ const cfg = await loadEffectiveConfig();
144
+ if (cfg?.seo?.sitemap?.disabled)
145
+ return errorResponse('Sitemap disabled', 404);
146
+ const base = siteUrlFromRequest(request, cfg);
147
+ const moduleSettings = resolveSeoModuleSettings(await getSeoOverrides(db()));
148
+ if (!moduleSettings.sitemapEnabled)
149
+ return errorResponse('Sitemap disabled', 404);
150
+ // Master switch: when the whole public site is opted out of indexing, the
151
+ // sitemap (a positive "please index these" signal) must be empty so it
152
+ // doesn't contradict the `Disallow: /` we emit in robots.txt.
153
+ if (moduleSettings.indexEntireSite === false) {
154
+ const emptyIndex = [
155
+ '<?xml version="1.0" encoding="UTF-8"?>',
156
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
157
+ '</sitemapindex>',
158
+ ].join('\n');
159
+ return new Response(emptyIndex, {
160
+ status: 200,
161
+ headers: {
162
+ 'Content-Type': 'application/xml; charset=utf-8',
163
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
164
+ },
165
+ });
166
+ }
167
+ const cols = sitemapEligibleCollections(cfg, {
168
+ includePosts: moduleSettings.includePostsInSitemap,
169
+ });
170
+ // Sitemap index lists Yoast-style public URLs (`/post-sitemap.xml`,
171
+ // `/post-sitemap2.xml`, …). Collections larger than SITEMAP_PAGE_SIZE are
172
+ // split across numbered files (Google's limit is 50k URLs / 50 MB per file).
173
+ const now = new Date().toISOString();
174
+ const perCollection = await Promise.all(cols.map(async (c) => {
175
+ let count = 0;
176
+ // Report the newest published change in the collection as the child
177
+ // sitemap's <lastmod> instead of "now". A lastmod that changes on
178
+ // every fetch trains crawlers to ignore it; an accurate one is the
179
+ // single most useful signal we can give them.
180
+ let lastmod = now;
181
+ try {
182
+ count = await db().document.count({
183
+ where: { collection: c.slug, deletedAt: null, status: 'PUBLISHED' },
184
+ });
185
+ const newest = await db().document.findFirst({
186
+ where: { collection: c.slug, deletedAt: null, status: 'PUBLISHED' },
187
+ select: { updatedAt: true },
188
+ orderBy: { updatedAt: 'desc' },
189
+ });
190
+ if (newest?.updatedAt)
191
+ lastmod = newest.updatedAt.toISOString();
192
+ }
193
+ catch {
194
+ count = 0;
195
+ }
196
+ // Skip collections that would render an empty `<urlset>`. A urlset with
197
+ // zero <url> entries violates the sitemaps.org schema and Search Console
198
+ // reports the child as an "empty sitemap", degrading trust in the whole
199
+ // index. A post-type collection with an archive path still renders that
200
+ // one self URL on page 0, so it is kept even at zero published docs.
201
+ const rendersArchiveUrl = c.type === 'post' && !!c.seo?.archivePath;
202
+ if (count === 0 && !rendersArchiveUrl)
203
+ return '';
204
+ const pages = Math.max(1, Math.ceil(count / SITEMAP_PAGE_SIZE));
205
+ const baseName = sitemapBaseName(c);
206
+ const entries = [];
207
+ for (let page = 0; page < pages; page++) {
208
+ const loc = collectionSitemapPublicUrl(base, baseName, page);
209
+ entries.push([
210
+ ' <sitemap>',
211
+ ` <loc>${escapeXml(loc)}</loc>`,
212
+ ` <lastmod>${lastmod}</lastmod>`,
213
+ ' </sitemap>',
214
+ ].join('\n'));
215
+ }
216
+ return entries.join('\n');
217
+ }));
218
+ const sitemaps = perCollection.filter(Boolean).join('\n');
219
+ const xml = [
220
+ '<?xml version="1.0" encoding="UTF-8"?>',
221
+ sitemapStylesheetPi(base, 'index'),
222
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
223
+ sitemaps,
224
+ '</sitemapindex>',
225
+ ].join('\n');
226
+ return new Response(xml, {
227
+ status: 200,
228
+ headers: {
229
+ 'Content-Type': 'application/xml; charset=utf-8',
230
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
231
+ },
232
+ });
233
+ }
234
+ catch (err) {
235
+ return internalError(err, 'sitemap.xml');
236
+ }
237
+ });
238
+ // Human-readable XSLT stylesheets for browser viewing (Yoast-style layout).
239
+ router.get('/sitemap.xsl', async () => {
240
+ return new Response(SITEMAP_URLSET_XSL, {
241
+ status: 200,
242
+ headers: {
243
+ 'Content-Type': 'application/xslt+xml; charset=utf-8',
244
+ 'Cache-Control': 'public, max-age=86400, s-maxage=86400',
245
+ },
246
+ });
247
+ });
248
+ router.get('/sitemap-index.xsl', async () => {
249
+ return new Response(SITEMAP_INDEX_XSL, {
250
+ status: 200,
251
+ headers: {
252
+ 'Content-Type': 'application/xslt+xml; charset=utf-8',
253
+ 'Cache-Control': 'public, max-age=86400, s-maxage=86400',
254
+ },
255
+ });
256
+ });
257
+ // The router's path-param syntax (`:name`) greedily matches everything up
258
+ // to the next `/`, so registering as `/sitemaps/:slug.xml` would capture
259
+ // `slug.xml` into a single param. We register `/sitemaps/:slug` instead and
260
+ // require the `.xml` suffix in the handler. Accepts Yoast-style names
261
+ // (`post-sitemap.xml`, `post-sitemap2.xml`) and legacy `{slug}.xml`.
262
+ router.get('/sitemaps/:slug', async (request, params) => {
263
+ try {
264
+ const cfg = await loadEffectiveConfig();
265
+ if (cfg?.seo?.sitemap?.disabled)
266
+ return errorResponse('Sitemap disabled', 404);
267
+ const slugParam = params.slug ?? '';
268
+ if (!/\.xml$/i.test(slugParam))
269
+ return errorResponse('Sitemap not found', 404);
270
+ const moduleSettings = resolveSeoModuleSettings(await getSeoOverrides(db()));
271
+ if (!moduleSettings.sitemapEnabled)
272
+ return errorResponse('Sitemap disabled', 404);
273
+ const eligible = sitemapEligibleCollections(cfg, {
274
+ includePosts: moduleSettings.includePostsInSitemap,
275
+ });
276
+ const resolved = resolveCollectionFromSitemapSlug(eligible, slugParam);
277
+ if (!resolved)
278
+ return errorResponse('Collection not found', 404);
279
+ const rawSlug = resolved.collection.slug;
280
+ const collection = cfg?.collections?.[rawSlug];
281
+ if (!collection)
282
+ return errorResponse('Collection not found', 404);
283
+ // Only publicly-rendered page/post collections are sitemap-eligible —
284
+ // structural/utility collections (menus, tags, templates) are not.
285
+ if (collection.type !== 'page' && collection.type !== 'post')
286
+ return errorResponse('Collection excluded from sitemap', 404);
287
+ if (collection.admin?.hidden)
288
+ return errorResponse('Collection excluded from sitemap', 404);
289
+ if (collection.seo?.excludeFromSitemap)
290
+ return errorResponse('Collection excluded from sitemap', 404);
291
+ // Master switch: whole public site opted out of indexing → empty urlset
292
+ // (mirrors the empty sitemap index + `Disallow: /` in robots.txt).
293
+ if (moduleSettings.indexEntireSite === false) {
294
+ const emptyUrlset = [
295
+ '<?xml version="1.0" encoding="UTF-8"?>',
296
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
297
+ '</urlset>',
298
+ ].join('\n');
299
+ return new Response(emptyUrlset, {
300
+ status: 200,
301
+ headers: {
302
+ 'Content-Type': 'application/xml; charset=utf-8',
303
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
304
+ },
305
+ });
306
+ }
307
+ // Honor the "Include posts in sitemap" crawl setting consistently with the
308
+ // sitemap index, so a post-type sitemap can't be reached when posts are
309
+ // excluded there.
310
+ if (collection.type === 'post' && !moduleSettings.includePostsInSitemap)
311
+ return errorResponse('Collection excluded from sitemap', 404);
312
+ const base = siteUrlFromRequest(request, cfg);
313
+ const environment = resolveSeoEnvironment();
314
+ // Yoast-style filenames encode the page (`post-sitemap2.xml` → page 1).
315
+ // Legacy `/sitemaps/posts.xml?page=N` still supported for backward compat.
316
+ let page = resolved.pageIndex;
317
+ if (!parseCollectionSitemapFilename(slugParam)) {
318
+ const pageParam = Number(new URL(request.url).searchParams.get('page') ?? '0');
319
+ if (Number.isFinite(pageParam) && pageParam > 0)
320
+ page = Math.floor(pageParam);
321
+ }
322
+ const docs = await db().document.findMany({
323
+ where: { collection: rawSlug, deletedAt: null, status: 'PUBLISHED' },
324
+ select: { slug: true, updatedAt: true, data: true, locale: true, localeGroupId: true },
325
+ orderBy: { updatedAt: 'desc' },
326
+ skip: page * SITEMAP_PAGE_SIZE,
327
+ take: SITEMAP_PAGE_SIZE,
328
+ });
329
+ // hreflang: when the site runs i18n with more than one locale, emit
330
+ // `<xhtml:link rel="alternate">` annotations so search engines serve the
331
+ // right language variant. Each translation shares a `localeGroupId`; its
332
+ // own `data.path`/slug yields the localized URL via resolveDocumentUrl, so
333
+ // this works regardless of the locale routing strategy. Skipped entirely
334
+ // (zero extra queries) for single-locale sites.
335
+ const i18nLocales = cfg?.i18n?.locales ?? [];
336
+ const i18nEnabled = i18nLocales.length > 1;
337
+ const defaultLocale = cfg?.i18n?.defaultLocale;
338
+ const alternatesByGroup = new Map();
339
+ if (i18nEnabled) {
340
+ const groupIds = [
341
+ ...new Set(docs.map((d) => d.localeGroupId).filter((g) => !!g)),
342
+ ];
343
+ if (groupIds.length > 0) {
344
+ const siblings = await db().document.findMany({
345
+ where: {
346
+ collection: rawSlug,
347
+ deletedAt: null,
348
+ status: 'PUBLISHED',
349
+ localeGroupId: { in: groupIds },
350
+ },
351
+ select: { slug: true, data: true, locale: true, localeGroupId: true },
352
+ });
353
+ for (const s of siblings) {
354
+ if (!s.localeGroupId)
355
+ continue;
356
+ const sData = s.data || {};
357
+ const loc = resolveDocumentUrl({
358
+ siteUrl: base,
359
+ urlPrefix: collection.urlPrefix,
360
+ slug: s.slug,
361
+ data: sData,
362
+ });
363
+ const list = alternatesByGroup.get(s.localeGroupId) ?? [];
364
+ list.push({ locale: s.locale, loc });
365
+ alternatesByGroup.set(s.localeGroupId, list);
366
+ }
367
+ }
368
+ }
369
+ const defaultPriority = collection.seo?.sitemapPriority ??
370
+ cfg?.seo?.sitemap?.defaultPriority ??
371
+ (collection.type === 'page' ? 0.8 : 0.6);
372
+ const changefreq = collection.seo?.sitemapChangeFreq ?? cfg?.seo?.sitemap?.defaultChangeFreq ?? 'weekly';
373
+ const urls = [];
374
+ let hreflangUsed = false;
375
+ let imagesUsed = false;
376
+ const includeImages = moduleSettings.includeImagesInSitemap === true;
377
+ const renderImages = (data) => {
378
+ if (!includeImages)
379
+ return [];
380
+ const imgs = collectDocumentImageUrls(data, base);
381
+ if (imgs.length === 0)
382
+ return [];
383
+ imagesUsed = true;
384
+ return imgs.map((u) => ` <image:image><image:loc>${escapeXml(u)}</image:loc></image:image>`);
385
+ };
386
+ const renderAlternates = (groupId) => {
387
+ if (!i18nEnabled || !groupId)
388
+ return [];
389
+ const alts = alternatesByGroup.get(groupId);
390
+ if (!alts || alts.length < 2)
391
+ return [];
392
+ hreflangUsed = true;
393
+ const lines = alts.map((a) => ` <xhtml:link rel="alternate" hreflang="${escapeXml(a.locale ?? defaultLocale ?? 'und')}" href="${escapeXml(a.loc)}" />`);
394
+ const fallback = alts.find((a) => a.locale === defaultLocale) ?? alts[0];
395
+ if (fallback) {
396
+ lines.push(` <xhtml:link rel="alternate" hreflang="x-default" href="${escapeXml(fallback.loc)}" />`);
397
+ }
398
+ return lines;
399
+ };
400
+ // Archive page first (e.g. /blog) for post-type collections — only on
401
+ // the first page so it isn't duplicated across paginated sitemap files.
402
+ if (page === 0 && collection.seo?.archivePath && collection.type === 'post') {
403
+ const archive = collection.seo.archivePath.startsWith('http')
404
+ ? collection.seo.archivePath
405
+ : `${base}${collection.seo.archivePath}`;
406
+ // The archive reflects its newest post, so derive lastmod from the most
407
+ // recently updated published doc rather than the current time.
408
+ const archiveLastmod = docs.reduce((newest, d) => {
409
+ const u = d.updatedAt instanceof Date ? d.updatedAt : null;
410
+ return u && (!newest || u > newest) ? u : newest;
411
+ }, null) ?? new Date();
412
+ urls.push([
413
+ ' <url>',
414
+ ` <loc>${escapeXml(archive)}</loc>`,
415
+ ` <lastmod>${archiveLastmod.toISOString()}</lastmod>`,
416
+ ` <changefreq>${changefreq}</changefreq>`,
417
+ ' <priority>0.6</priority>',
418
+ ' </url>',
419
+ ].join('\n'));
420
+ }
421
+ for (const d of docs) {
422
+ const data = d.data || {};
423
+ const slug = d.slug ?? data.slug;
424
+ // An explicit `data.path` can stand on its own (e.g. the homepage at
425
+ // "/"), so only require a slug when there's no canonical path set.
426
+ const hasExplicitPath = typeof data.path === 'string' && data.path.trim() !== '';
427
+ if (!slug && !hasExplicitPath)
428
+ continue;
429
+ // Never list a noindexed URL — it conflicts with the page's own robots
430
+ // meta tag and wastes crawl budget.
431
+ if (sitemapDocumentNoIndex(data, collection.seo, cfg?.seo, environment))
432
+ continue;
433
+ const loc = resolveDocumentUrl({
434
+ siteUrl: base,
435
+ urlPrefix: collection.urlPrefix,
436
+ slug,
437
+ data,
438
+ });
439
+ urls.push([
440
+ ' <url>',
441
+ ` <loc>${escapeXml(loc)}</loc>`,
442
+ ` <lastmod>${d.updatedAt?.toISOString() ?? new Date().toISOString()}</lastmod>`,
443
+ ` <changefreq>${changefreq}</changefreq>`,
444
+ ` <priority>${defaultPriority.toFixed(1)}</priority>`,
445
+ ...renderAlternates(d.localeGroupId),
446
+ ...renderImages(data),
447
+ ' </url>',
448
+ ].join('\n'));
449
+ }
450
+ const urlsetOpen = [
451
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"',
452
+ hreflangUsed ? ' xmlns:xhtml="http://www.w3.org/1999/xhtml"' : '',
453
+ imagesUsed ? ` xmlns:image="${SITEMAP_IMAGE_NS}"` : '',
454
+ '>',
455
+ ].join('');
456
+ const xml = [
457
+ '<?xml version="1.0" encoding="UTF-8"?>',
458
+ sitemapStylesheetPi(base, 'urlset'),
459
+ urlsetOpen,
460
+ urls.join('\n'),
461
+ '</urlset>',
462
+ ].join('\n');
463
+ return new Response(xml, {
464
+ status: 200,
465
+ headers: {
466
+ 'Content-Type': 'application/xml; charset=utf-8',
467
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
468
+ },
469
+ });
470
+ }
471
+ catch (err) {
472
+ return internalError(err, 'sitemaps/:slug.xml');
473
+ }
474
+ });
475
+ // ---------------------------------------------------------------------------
476
+ // Content feeds: RSS 2.0 (/feed.xml) + JSON Feed 1.1 (/feed.json).
477
+ //
478
+ // Newest published items across post-type collections (falling back to pages
479
+ // when a site has no post collections), excluding per-document noindex. Unlike
480
+ // the sitemap these are a subscription/distribution surface, not a crawl
481
+ // directive, so they are not gated by `indexEntireSite`.
482
+ // ---------------------------------------------------------------------------
483
+ const FEED_LIMIT = 50;
484
+ async function gatherFeedItems(cfg, base) {
485
+ const { resolveDocumentUrl } = await import('../../seo/page-meta.js');
486
+ const environment = resolveSeoEnvironment();
487
+ const siteSeo = cfg?.seo;
488
+ const all = sitemapEligibleCollections(cfg);
489
+ const posts = all.filter((c) => c.type === 'post');
490
+ const cols = posts.length > 0 ? posts : all;
491
+ const collected = [];
492
+ for (const c of cols) {
493
+ let docs = [];
494
+ try {
495
+ docs = await db().document.findMany({
496
+ where: { collection: c.slug, deletedAt: null, status: 'PUBLISHED' },
497
+ select: { slug: true, title: true, data: true, publishedAt: true, updatedAt: true },
498
+ orderBy: { publishedAt: 'desc' },
499
+ take: FEED_LIMIT,
500
+ });
501
+ }
502
+ catch {
503
+ docs = [];
504
+ }
505
+ for (const d of docs) {
506
+ const data = d.data || {};
507
+ if (sitemapDocumentNoIndex(data, c.seo, siteSeo, environment))
508
+ continue;
509
+ const url = resolveDocumentUrl({
510
+ siteUrl: base,
511
+ urlPrefix: c.urlPrefix,
512
+ slug: d.slug,
513
+ data,
514
+ });
515
+ const { resolveEffectiveMeta } = await import('../../seo/page-meta.js');
516
+ const effective = resolveEffectiveMeta({
517
+ data,
518
+ docTitle: d.title,
519
+ publishedAt: d.publishedAt,
520
+ collection: c,
521
+ collectionSlug: c.slug,
522
+ site: siteSeo,
523
+ siteUrl: base,
524
+ });
525
+ const title = effective.metaTitle ?? d.title ?? 'Untitled';
526
+ const description = (typeof data.keyTakeaway === 'string' && data.keyTakeaway) ||
527
+ (typeof data.metaDescription === 'string' && data.metaDescription) ||
528
+ (typeof data.excerpt === 'string' ? data.excerpt : '') ||
529
+ undefined;
530
+ const date = (d.publishedAt ?? d.updatedAt)?.toISOString();
531
+ const modified = d.updatedAt?.toISOString();
532
+ // Only advertise a modification time when it is genuinely newer than
533
+ // publication, so unchanged posts don't look perpetually "updated".
534
+ const dateModified = modified && date && modified > date ? modified : undefined;
535
+ // Carry the rendered article body (HTML) when available so subscribers
536
+ // receive the whole post, not just a summary. Emitted as
537
+ // <content:encoded> / content_html by the feed builders.
538
+ const content = (typeof data.body === 'string' && data.body) ||
539
+ (typeof data.content === 'string' && data.content) ||
540
+ undefined;
541
+ collected.push({ url, title, description, content, date, dateModified });
542
+ }
543
+ }
544
+ // Merge collections and keep the globally newest items.
545
+ collected.sort((a, b) => (b.date ?? '').localeCompare(a.date ?? ''));
546
+ return collected.slice(0, FEED_LIMIT);
547
+ }
548
+ router.get('/feed.xml', async (request) => {
549
+ try {
550
+ const cfg = await loadEffectiveConfig();
551
+ const base = siteUrlFromRequest(request, cfg);
552
+ const items = await gatherFeedItems(cfg, base);
553
+ const { buildRssFeed } = await import('../../seo/feeds.js');
554
+ const xml = buildRssFeed({
555
+ title: cfg?.seo?.siteName || 'Site',
556
+ homeUrl: base || '/',
557
+ feedUrl: `${base}/feed.xml`,
558
+ description: cfg?.seo?.defaultMetaDescription,
559
+ updated: items[0]?.date,
560
+ language: cfg?.i18n?.defaultLocale,
561
+ }, items);
562
+ return new Response(xml, {
563
+ status: 200,
564
+ headers: {
565
+ 'Content-Type': 'application/rss+xml; charset=utf-8',
566
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
567
+ },
568
+ });
569
+ }
570
+ catch (err) {
571
+ return internalError(err, 'feed.xml');
572
+ }
573
+ });
574
+ router.get('/feed.json', async (request) => {
575
+ try {
576
+ const cfg = await loadEffectiveConfig();
577
+ const base = siteUrlFromRequest(request, cfg);
578
+ const items = await gatherFeedItems(cfg, base);
579
+ const { buildJsonFeed } = await import('../../seo/feeds.js');
580
+ const body = buildJsonFeed({
581
+ title: cfg?.seo?.siteName || 'Site',
582
+ homeUrl: base || '/',
583
+ feedUrl: `${base}/feed.json`,
584
+ description: cfg?.seo?.defaultMetaDescription,
585
+ updated: items[0]?.date,
586
+ language: cfg?.i18n?.defaultLocale,
587
+ }, items);
588
+ return new Response(body, {
589
+ status: 200,
590
+ headers: {
591
+ 'Content-Type': 'application/feed+json; charset=utf-8',
592
+ 'Cache-Control': 'public, max-age=300, s-maxage=600',
593
+ },
594
+ });
595
+ }
596
+ catch (err) {
597
+ return internalError(err, 'feed.json');
598
+ }
599
+ });
600
+ router.get('/robots.txt', async (request) => {
601
+ try {
602
+ const cfg = await loadEffectiveConfig();
603
+ const seo = cfg?.seo;
604
+ if (seo?.robots?.disabled)
605
+ return errorResponse('robots.txt disabled', 404);
606
+ // Read SEO module settings up-front: they drive the custom-body override,
607
+ // the `robotsEnabled` kill-switch, and the `indexEntireSite` master toggle.
608
+ let settings;
609
+ try {
610
+ settings = resolveSeoModuleSettings(await getSeoOverrides(db()));
611
+ }
612
+ catch {
613
+ // Fall back to defaults (indexable) on any override-read failure.
614
+ settings = resolveSeoModuleSettings(null);
615
+ }
616
+ if (settings.robotsEnabled === false)
617
+ return errorResponse('robots.txt disabled', 404);
618
+ // Admin-edited custom robots.txt body (Technical tab) wins when set —
619
+ // the editor is the single source of truth for operators who want full
620
+ // control over directives.
621
+ const custom = settings.robotsTxt?.trim();
622
+ if (custom) {
623
+ return new Response(settings.robotsTxt, {
624
+ status: 200,
625
+ headers: {
626
+ 'Content-Type': 'text/plain; charset=utf-8',
627
+ 'Cache-Control': 'public, max-age=3600, s-maxage=3600',
628
+ },
629
+ });
630
+ }
631
+ const base = siteUrlFromRequest(request, cfg);
632
+ // `indexEntireSite` is the public-site master switch. When OFF we emit a
633
+ // blanket `Disallow: /` for all crawlers (which already covers /admin and
634
+ // /api) and stop advertising the sitemap — the operator has opted the
635
+ // whole public site out of indexing. This only ever tightens crawling; it
636
+ // never affects CMS admin/API protection, which is enforced by auth + the
637
+ // admin's own `noindex` meta tag regardless of this file.
638
+ const indexable = settings.indexEntireSite !== false;
639
+ // Advertise the canonical public sitemap URL (`/sitemap.xml`), not the
640
+ // internal `/api/cms/sitemap.xml` mount. Consumer sites proxy the root
641
+ // path to the CMS route; the rest of the SEO subsystem (search-engine
642
+ // pings, index status, llms.txt) already standardizes on `/sitemap.xml`.
643
+ const sitemapUrl = !indexable || seo?.sitemap?.disabled ? undefined : `${base}/sitemap.xml`;
644
+ // Allow the default og:image endpoint (`/api/cms/og.png`) with a
645
+ // more-specific rule BEFORE the blanket /api/ disallow (Google & Bing
646
+ // honor the longest match) — otherwise the very crawlers that render
647
+ // share cards (Googlebot-Image, Twitterbot, facebookexternalhit,
648
+ // Slackbot) are told not to fetch it, so shared links show no card image.
649
+ const lines = indexable
650
+ ? [
651
+ 'User-agent: *',
652
+ 'Allow: /',
653
+ 'Disallow: /admin',
654
+ 'Allow: /api/cms/og.png',
655
+ 'Disallow: /api/',
656
+ '',
657
+ ]
658
+ : ['User-agent: *', 'Disallow: /', ''];
659
+ for (const rule of seo?.robots?.additionalRules ?? []) {
660
+ lines.push(`User-agent: ${rule.userAgent}`);
661
+ for (const allow of rule.allow ?? [])
662
+ lines.push(`Allow: ${allow}`);
663
+ for (const dis of rule.disallow ?? [])
664
+ lines.push(`Disallow: ${dis}`);
665
+ // Per-UA rate limit (seconds). Honored by Bing/Yandex/Seznam; ignored by
666
+ // Google (which uses Search Console instead). Only emit a sane positive
667
+ // value so a stray 0/NaN can't produce a meaningless directive.
668
+ if (typeof rule.crawlDelay === 'number' &&
669
+ Number.isFinite(rule.crawlDelay) &&
670
+ rule.crawlDelay > 0)
671
+ lines.push(`Crawl-delay: ${rule.crawlDelay}`);
672
+ lines.push('');
673
+ }
674
+ // Nuanced AI-crawler policy (training vs retrieval), falling back to the
675
+ // legacy `blockAIBots` boolean. Only emitted when the site is indexable —
676
+ // when the master switch is off, the blanket `Disallow: /` above already
677
+ // covers every crawler.
678
+ if (indexable) {
679
+ lines.push(...buildAiBotRobotsLines(seo?.robots?.aiPolicy, seo?.robots?.blockAIBots));
680
+ }
681
+ if (sitemapUrl)
682
+ lines.push(`Sitemap: ${sitemapUrl}`, '');
683
+ return new Response(lines.join('\n'), {
684
+ status: 200,
685
+ headers: {
686
+ 'Content-Type': 'text/plain; charset=utf-8',
687
+ 'Cache-Control': 'public, max-age=3600, s-maxage=3600',
688
+ },
689
+ });
690
+ }
691
+ catch (err) {
692
+ return internalError(err, 'robots.txt');
693
+ }
694
+ });
695
+ // IndexNow key verification file. IndexNow (Bing, Yandex, Seznam, Naver, …)
696
+ // requires the submitting key to be retrievable from the same host; we serve
697
+ // it here and advertise this path as `keyLocation` when submitting. The key
698
+ // comes from the `INDEXNOW_KEY` env var — when unset, IndexNow is disabled and
699
+ // this returns 404. The key is a public verification token by design (it's
700
+ // embedded in every submission), so serving it is not a secret leak.
701
+ router.get('/indexnow-key.txt', async () => {
702
+ try {
703
+ const key = process.env.INDEXNOW_KEY?.trim();
704
+ if (!key)
705
+ return errorResponse('IndexNow not configured', 404);
706
+ return new Response(key, {
707
+ status: 200,
708
+ headers: {
709
+ 'Content-Type': 'text/plain; charset=utf-8',
710
+ 'Cache-Control': 'public, max-age=3600, s-maxage=3600',
711
+ },
712
+ });
713
+ }
714
+ catch (err) {
715
+ return internalError(err, 'indexnow-key.txt');
716
+ }
717
+ });
718
+ router.get('/og.png', async (request) => {
719
+ try {
720
+ const cfg = await loadEffectiveConfig();
721
+ if (cfg?.seo?.ogImage?.disabled)
722
+ return errorResponse('og.png disabled', 404);
723
+ const url = new URL(request.url);
724
+ const title = url.searchParams.get('title') ?? cfg?.seo?.siteName ?? 'Untitled';
725
+ const description = url.searchParams.get('description') ?? undefined;
726
+ const siteName = url.searchParams.get('siteName') ?? cfg?.seo?.siteName;
727
+ const theme = url.searchParams.get('theme') ?? cfg?.seo?.ogImage?.theme ?? 'light';
728
+ const bg = theme === 'dark' ? '#0a0a0a' : '#ffffff';
729
+ const fg = theme === 'dark' ? '#fafafa' : '#0a0a0a';
730
+ const muted = theme === 'dark' ? '#a1a1aa' : '#71717a';
731
+ // SVG OG image. Crawlers (Facebook, Twitter/X, LinkedIn, Slack, Discord)
732
+ // all accept image/svg+xml when served with the right Content-Type. We
733
+ // chose SVG over PNG to avoid forcing a Satori/resvg dependency on
734
+ // every integrator; sites that need PNG can override with `og:image`
735
+ // pointing at their own /og endpoint built with @vercel/og.
736
+ const svg = renderOgSvg({ title, description, siteName, theme, bg, fg, muted });
737
+ return new Response(svg, {
738
+ status: 200,
739
+ headers: {
740
+ 'Content-Type': 'image/svg+xml; charset=utf-8',
741
+ 'Cache-Control': 'public, max-age=86400, s-maxage=86400',
742
+ },
743
+ });
744
+ }
745
+ catch (err) {
746
+ return internalError(err, 'og.png');
747
+ }
748
+ });
749
+ router.get('/seo/schema/:documentId', async (request, params) => {
750
+ try {
751
+ const auth = await requireAuth(request);
752
+ if (auth.error)
753
+ return auth.error;
754
+ const doc = await db().document.findFirst({
755
+ where: { id: params.documentId, deletedAt: null },
756
+ });
757
+ if (!doc)
758
+ return errorResponse('Not found', 404);
759
+ const accessErr = await enforceDocumentReadAccess(auth.session, doc.collection);
760
+ if (accessErr)
761
+ return accessErr;
762
+ const { buildSchemaGraph } = await import('../../content/structured-data.js');
763
+ const data = doc.data || {};
764
+ const graph = buildSchemaGraph({
765
+ siteName: 'Prenta CMS',
766
+ siteUrl: '',
767
+ }, {
768
+ url: `/${doc.collection}/${doc.slug || ''}`,
769
+ title: doc.title || data.title || '',
770
+ description: data.metaDescription || data.seoDescription || '',
771
+ datePublished: (doc.publishedAt ?? doc.createdAt)?.toISOString(),
772
+ dateModified: doc.updatedAt?.toISOString(),
773
+ type: doc.collection === 'posts' ? 'post' : 'page',
774
+ keywords: data.tags || data.keywords,
775
+ featuredImage: data.featuredImage ? { url: data.featuredImage } : undefined,
776
+ });
777
+ return new Response(JSON.stringify(graph), {
778
+ status: 200,
779
+ headers: { 'Content-Type': 'application/json' },
780
+ });
781
+ }
782
+ catch (err) {
783
+ return internalError(err, 'seo/schema');
784
+ }
785
+ });
786
+ router.get('/seo/meta/:documentId', async (request, params) => {
787
+ try {
788
+ const auth = await requireAuth(request);
789
+ if (auth.error)
790
+ return auth.error;
791
+ const doc = await db().document.findFirst({
792
+ where: { id: params.documentId, deletedAt: null },
793
+ });
794
+ if (!doc)
795
+ return errorResponse('Not found', 404);
796
+ const accessErr = await enforceDocumentReadAccess(auth.session, doc.collection);
797
+ if (accessErr)
798
+ return accessErr;
799
+ const { composePageMeta } = await import('../../seo/page-meta.js');
800
+ const { getSeoOverrides, applySeoOverrides } = await import('../../seo/config-store.js');
801
+ const data = doc.data || {};
802
+ const pageSettings = (data.pageSettings ?? data._pageSettings);
803
+ const cfg = applySeoOverrides(getPrentaConfig(), await getSeoOverrides(db()));
804
+ const collectionDef = cfg?.collections?.[doc.collection] ?? null;
805
+ const composed = composePageMeta({
806
+ doc: {
807
+ id: doc.id,
808
+ collection: doc.collection,
809
+ slug: doc.slug,
810
+ data,
811
+ publishedAt: doc.publishedAt,
812
+ updatedAt: doc.updatedAt,
813
+ structuredData: doc.structuredData ?? null,
814
+ pageSettings: pageSettings ?? null,
815
+ },
816
+ collection: collectionDef,
817
+ config: cfg ?? null,
818
+ });
819
+ return new Response(JSON.stringify(composed.meta), {
820
+ status: 200,
821
+ headers: { 'Content-Type': 'application/json' },
822
+ });
823
+ }
824
+ catch (err) {
825
+ return internalError(err, 'seo/meta');
826
+ }
827
+ });
828
+ // ---------------------------------------------------------------------------
829
+ // SEO summary (aggregated dashboard data)
830
+ // ---------------------------------------------------------------------------
831
+ router.get('/seo/summary', async (request) => {
832
+ try {
833
+ const auth = await requireAuth(request);
834
+ if (auth.error)
835
+ return auth.error;
836
+ // EDITOR+ only — this endpoint issues outbound GET probes for link
837
+ // health, mirroring the role gate on /seo/link-health.
838
+ const roleErr = requireRole(auth.session.role, WRITE_ROLES);
839
+ if (roleErr)
840
+ return roleErr;
841
+ const docs = (await safeFindMany(db().document, {
842
+ where: { deletedAt: null, status: 'PUBLISHED' },
843
+ select: { id: true, title: true, collection: true, data: true, plainText: true },
844
+ orderBy: { updatedAt: 'desc' },
845
+ take: 50,
846
+ }));
847
+ let missingMetaDescriptions = 0;
848
+ let missingAltText = 0;
849
+ const topContent = [];
850
+ for (const doc of docs) {
851
+ const data = doc.data ?? {};
852
+ if (!data.metaDescription && !data.seoDescription)
853
+ missingMetaDescriptions++;
854
+ const content = typeof data.body === 'string'
855
+ ? data.body
856
+ : typeof data.content === 'string'
857
+ ? data.content
858
+ : '';
859
+ if (content) {
860
+ const imgMatches = content.match(/<img\b[^>]*>/gi) ?? [];
861
+ const noAlt = imgMatches.filter((img) => !img.includes('alt=')).length;
862
+ if (noAlt > 0)
863
+ missingAltText += noAlt;
864
+ }
865
+ topContent.push({
866
+ id: doc.id,
867
+ title: doc.title ?? 'Untitled',
868
+ collection: doc.collection,
869
+ score: computeLightSeoScore(data),
870
+ });
871
+ }
872
+ topContent.sort((a, b) => b.score - a.score);
873
+ let brokenInternalLinks = 0;
874
+ try {
875
+ const siteUrl = (process.env.NEXT_PUBLIC_SITE_URL ?? '').replace(/\/+$/, '');
876
+ // Only probe internal links (same-origin as the configured site). When
877
+ // NEXT_PUBLIC_SITE_URL is unset we can't classify any URL as internal,
878
+ // so we skip all probing rather than issuing requests to arbitrary,
879
+ // document-controlled hosts — that would be an SSRF oracle.
880
+ if (siteUrl) {
881
+ const linkDocs = docs.slice(0, 10);
882
+ for (const doc of linkDocs) {
883
+ const urls = extractOutboundUrlsFromDocumentData(doc.data ?? {});
884
+ const seen = new Set();
885
+ for (const clean of urls) {
886
+ if (seen.has(clean) || !clean.startsWith(siteUrl))
887
+ continue;
888
+ seen.add(clean);
889
+ try {
890
+ // safeFetch rejects private/loopback IPs and disables redirect
891
+ // following, so even an internal link can't smuggle the probe
892
+ // onto the internal network.
893
+ const resp = await safeFetch(clean, {
894
+ method: 'GET',
895
+ headers: { ...LINK_PROBE_HEADERS },
896
+ timeoutMs: 3000,
897
+ });
898
+ try {
899
+ await resp.body?.cancel();
900
+ }
901
+ catch {
902
+ /* noop */
903
+ }
904
+ if (isLinkProbeIssueStatus(resp.status)) {
905
+ brokenInternalLinks++;
906
+ }
907
+ }
908
+ catch (err) {
909
+ if (err instanceof SsrfBlockedError)
910
+ continue;
911
+ brokenInternalLinks++;
912
+ }
913
+ }
914
+ }
915
+ }
916
+ }
917
+ catch {
918
+ /* best effort */
919
+ }
920
+ return json({
921
+ data: {
922
+ totalPages: docs.length,
923
+ issuesSummary: { missingMetaDescriptions, brokenInternalLinks, missingAltText },
924
+ topContent: topContent.slice(0, 10),
925
+ },
926
+ });
927
+ }
928
+ catch (err) {
929
+ return internalError(err);
930
+ }
931
+ });
932
+ // ---------------------------------------------------------------------------
933
+ // SEO config (admin-editable overrides for `prenta.config.ts` seo defaults)
934
+ // ---------------------------------------------------------------------------
935
+ /** Public apex for View live / View Site — any authenticated session. */
936
+ router.get('/site/public-url', async (request) => {
937
+ try {
938
+ const auth = await requireAuth(request);
939
+ if (auth.error)
940
+ return auth.error;
941
+ const { resolvePublicSiteUrl } = await import('../../seo/public-site-url.js');
942
+ const result = await resolvePublicSiteUrl();
943
+ return json({ data: result });
944
+ }
945
+ catch (err) {
946
+ return internalError(err, 'site/public-url GET');
947
+ }
948
+ });
949
+ /**
950
+ * Returns:
951
+ * - `static` → the SEO config from `prenta.config.ts` (read-only, code-level)
952
+ * - `overrides` → the user-edited DB overrides (or null on first boot)
953
+ * - `effective` → static + overrides merged (what the runtime actually uses)
954
+ * - `collections` → list of collection slugs + labels the UI should iterate
955
+ *
956
+ * The UI uses `static` to show grey "default" placeholders, `overrides` to
957
+ * populate the form inputs, and writes back just the changed fields via PUT.
958
+ */
959
+ router.get('/seo/config', async (request) => {
960
+ try {
961
+ const auth = await requireAuth(request);
962
+ if (auth.error)
963
+ return auth.error;
964
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
965
+ if (roleErr)
966
+ return roleErr;
967
+ const { getSeoOverrides, applySeoOverrides } = await import('../../seo/config-store.js');
968
+ const staticCfg = getPrentaConfig();
969
+ const overrides = await getSeoOverrides(db());
970
+ const effective = applySeoOverrides(staticCfg, overrides);
971
+ const collections = Object.entries(staticCfg?.collections ?? {})
972
+ .map(([slug, col]) => ({
973
+ slug,
974
+ label: col.labels?.plural ?? slug,
975
+ type: col.type ?? 'page',
976
+ urlPrefix: col.urlPrefix,
977
+ staticSeo: col.seo ?? null,
978
+ effectiveSeo: effective?.collections?.[slug]?.seo ?? null,
979
+ }))
980
+ .sort((a, b) => a.label.localeCompare(b.label));
981
+ return json({
982
+ data: {
983
+ static: { site: staticCfg?.seo ?? null },
984
+ overrides: overrides ?? null,
985
+ effective: { site: effective?.seo ?? null },
986
+ collections,
987
+ },
988
+ });
989
+ }
990
+ catch (err) {
991
+ return internalError(err, 'seo/config GET');
992
+ }
993
+ });
994
+ router.put('/seo/config', async (request) => {
995
+ try {
996
+ const auth = await requireAuth(request);
997
+ if (auth.error)
998
+ return auth.error;
999
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1000
+ if (roleErr)
1001
+ return roleErr;
1002
+ const body = (await request.json().catch(() => null));
1003
+ if (!body || typeof body !== 'object') {
1004
+ return errorResponse('Request body must be an object', 400);
1005
+ }
1006
+ // Shallow shape validation — we don't want to mirror the entire type
1007
+ // here (the config-store merger ignores unknown keys anyway), but we do
1008
+ // want to reject obviously malformed payloads early so the UI gets a
1009
+ // clear 400 instead of a silent no-op.
1010
+ const site = body.site && typeof body.site === 'object' ? body.site : undefined;
1011
+ const collections = body.collections && typeof body.collections === 'object' ? body.collections : undefined;
1012
+ if (site === undefined && collections === undefined) {
1013
+ return errorResponse('Body must include at least one of `site` or `collections`', 400);
1014
+ }
1015
+ // Validate the title template server-side so an unsupported token can't be
1016
+ // persisted and then silently break public title rendering.
1017
+ if (site && typeof site.titleTemplate === 'string') {
1018
+ const { validateTitleTemplate } = await import('../../seo/title-templates.js');
1019
+ const result = validateTitleTemplate(site.titleTemplate);
1020
+ if (!result.valid) {
1021
+ return errorResponse(result.errors.join(' '), 400);
1022
+ }
1023
+ }
1024
+ const { putSeoOverrides, getSeoOverrides } = await import('../../seo/config-store.js');
1025
+ // Merge with whatever's currently stored so the UI can PATCH a single
1026
+ // section without wiping the other — `PUT /seo/config { site: {...} }`
1027
+ // shouldn't blow away per-collection settings.
1028
+ const current = (await getSeoOverrides(db())) ?? {};
1029
+ const next = {
1030
+ site: site !== undefined ? site : current.site,
1031
+ collections: collections !== undefined
1032
+ ? { ...(current.collections ?? {}), ...collections }
1033
+ : current.collections,
1034
+ // Preserve Technical-tab module settings so editing site/collection
1035
+ // defaults never silently wipes crawl/robots/sitemap configuration.
1036
+ module: current.module,
1037
+ };
1038
+ const saved = await putSeoOverrides(db(), next, auth.session.userId);
1039
+ // Audit so changes to public SEO surface are traceable. We log a
1040
+ // field-level diff (previous → new) for the site defaults, but redact
1041
+ // verification token VALUES — only record which providers changed, never
1042
+ // the token itself, since those land in public <meta> tags and shouldn't
1043
+ // be duplicated into the audit trail.
1044
+ try {
1045
+ const { resolveSeoEnvironment } = await import('../../seo/robots.js');
1046
+ const prevSite = (current.site ?? {});
1047
+ const nextSite = (site ?? prevSite);
1048
+ const changedFields = [];
1049
+ for (const key of new Set([...Object.keys(prevSite), ...Object.keys(nextSite)])) {
1050
+ if (key === 'verification')
1051
+ continue;
1052
+ if (JSON.stringify(prevSite[key]) !== JSON.stringify(nextSite[key])) {
1053
+ changedFields.push({
1054
+ field: key,
1055
+ from: prevSite[key] ?? null,
1056
+ to: nextSite[key] ?? null,
1057
+ });
1058
+ }
1059
+ }
1060
+ const prevVer = (prevSite.verification ?? {});
1061
+ const nextVer = (nextSite.verification ?? {});
1062
+ const verificationChanged = Object.keys({ ...prevVer, ...nextVer }).filter((k) => JSON.stringify(prevVer[k]) !== JSON.stringify(nextVer[k]));
1063
+ await logEvent({
1064
+ event: 'update_seo_config',
1065
+ userId: auth.session.userId,
1066
+ details: {
1067
+ changedFields,
1068
+ verificationChanged,
1069
+ collectionKeys: Object.keys(collections ?? {}),
1070
+ environment: resolveSeoEnvironment(),
1071
+ source: 'settings.seo',
1072
+ },
1073
+ });
1074
+ }
1075
+ catch {
1076
+ // Audit failures must never block the write.
1077
+ }
1078
+ return json({ data: saved });
1079
+ }
1080
+ catch (err) {
1081
+ return internalError(err, 'seo/config PUT');
1082
+ }
1083
+ });
1084
+ // Effective, computed crawl/index status for the General Settings card.
1085
+ // Reads the SAME effective SEO config the public renderer uses, so the badge
1086
+ // shown to editors never drifts from what search engines actually see.
1087
+ router.get('/seo/index-status', async (request) => {
1088
+ try {
1089
+ const auth = await requireAuth(request);
1090
+ if (auth.error)
1091
+ return auth.error;
1092
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1093
+ if (roleErr)
1094
+ return roleErr;
1095
+ const { getSiteIndexStatus } = await import('../../seo/index-status.js');
1096
+ const status = await getSiteIndexStatus(db());
1097
+ return json({ data: status });
1098
+ }
1099
+ catch (err) {
1100
+ return internalError(err, 'seo/index-status GET');
1101
+ }
1102
+ });
1103
+ // ---------------------------------------------------------------------------
1104
+ // Technical SEO — sitemap status, crawl settings, robots.txt editor.
1105
+ // All backed by the `module` block of the SEO overrides document.
1106
+ // ---------------------------------------------------------------------------
1107
+ /** Persist a partial patch onto the SEO module settings, preserving the rest. */
1108
+ async function patchSeoModule(patch, userId) {
1109
+ const { getSeoOverrides, putSeoOverrides } = await import('../../seo/config-store.js');
1110
+ const current = (await getSeoOverrides(db())) ?? {};
1111
+ await putSeoOverrides(db(), {
1112
+ site: current.site,
1113
+ collections: current.collections,
1114
+ module: { ...(current.module ?? {}), ...patch },
1115
+ }, userId);
1116
+ }
1117
+ /** Build the default robots.txt body (mirrors the public /robots.txt route). */
1118
+ function buildDefaultRobots(request, cfg, settings) {
1119
+ const base = siteUrlFromRequest(request, cfg);
1120
+ const indexable = settings.indexEntireSite !== false;
1121
+ const sitemapUrl = !indexable || cfg?.seo?.sitemap?.disabled ? undefined : `${base}/sitemap.xml`;
1122
+ const lines = indexable
1123
+ ? ['User-agent: *', 'Allow: /', 'Disallow: /admin', 'Disallow: /api/', '']
1124
+ : ['User-agent: *', 'Disallow: /', ''];
1125
+ if (indexable) {
1126
+ lines.push(...buildAiBotRobotsLines(cfg?.seo?.robots?.aiPolicy, cfg?.seo?.robots?.blockAIBots));
1127
+ }
1128
+ if (sitemapUrl)
1129
+ lines.push(`Sitemap: ${sitemapUrl}`, '');
1130
+ return lines.join('\n');
1131
+ }
1132
+ router.get('/seo/sitemap/status', async (request) => {
1133
+ try {
1134
+ const auth = await requireAuth(request);
1135
+ if (auth.error)
1136
+ return auth.error;
1137
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1138
+ if (roleErr)
1139
+ return roleErr;
1140
+ const { getSeoOverrides, resolveSeoModuleSettings } = await import('../../seo/config-store.js');
1141
+ const cfg = await loadEffectiveConfig();
1142
+ const settings = resolveSeoModuleSettings(await getSeoOverrides(db()));
1143
+ const base = siteUrlFromRequest(request, cfg);
1144
+ const environment = resolveSeoEnvironment();
1145
+ const cols = sitemapEligibleCollections(cfg, { includePosts: settings.includePostsInSitemap });
1146
+ // Run the SAME noindex resolution the sitemap renderer uses
1147
+ // (sitemapDocumentNoIndex → pageSettings/robots/collection/site/env), so
1148
+ // the "excluded" badge matches what search engines actually see. A single
1149
+ // JSON path filter on `data.noindex` never agreed with the real exclusion
1150
+ // logic and reported 0 even when many pages were correctly withheld.
1151
+ let pagesIncluded = 0;
1152
+ let pagesExcluded = 0;
1153
+ for (const col of cols) {
1154
+ const colSeo = cfg?.collections?.[col.slug]?.seo ?? col.seo;
1155
+ try {
1156
+ const docs = await db().document.findMany({
1157
+ where: { collection: col.slug, deletedAt: null, status: 'PUBLISHED' },
1158
+ select: { data: true },
1159
+ });
1160
+ for (const d of docs) {
1161
+ const data = d.data || {};
1162
+ if (sitemapDocumentNoIndex(data, colSeo, cfg?.seo, environment))
1163
+ pagesExcluded++;
1164
+ else
1165
+ pagesIncluded++;
1166
+ }
1167
+ }
1168
+ catch {
1169
+ /* best-effort: leave counts as-is for this collection */
1170
+ }
1171
+ }
1172
+ const warnings = [];
1173
+ if (!settings.sitemapEnabled)
1174
+ warnings.push('Sitemap generation is disabled in crawl settings.');
1175
+ if (pagesIncluded === 0)
1176
+ warnings.push('No published pages are eligible for the sitemap.');
1177
+ return json({
1178
+ data: {
1179
+ sitemapUrl: `${base}/sitemap.xml`,
1180
+ lastGeneratedAt: settings.sitemapLastGeneratedAt,
1181
+ pagesIncluded,
1182
+ pagesExcluded,
1183
+ autoRegenerateOnPublish: settings.autoRegenerateSitemapOnPublish,
1184
+ errors: [],
1185
+ warnings,
1186
+ },
1187
+ });
1188
+ }
1189
+ catch (err) {
1190
+ return internalError(err, 'seo/sitemap/status');
1191
+ }
1192
+ });
1193
+ router.post('/seo/sitemap/regenerate', async (request) => {
1194
+ try {
1195
+ const auth = await requireAuth(request);
1196
+ if (auth.error)
1197
+ return auth.error;
1198
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1199
+ if (roleErr)
1200
+ return roleErr;
1201
+ const now = new Date().toISOString();
1202
+ await patchSeoModule({ sitemapLastGeneratedAt: now }, auth.session.userId);
1203
+ const { getSeoOverrides, resolveSeoModuleSettings } = await import('../../seo/config-store.js');
1204
+ const cfg = await loadEffectiveConfig();
1205
+ const settings = resolveSeoModuleSettings(await getSeoOverrides(db()));
1206
+ const base = siteUrlFromRequest(request, cfg);
1207
+ const cols = sitemapEligibleCollections(cfg, { includePosts: settings.includePostsInSitemap });
1208
+ let pagesIncluded = 0;
1209
+ for (const col of cols) {
1210
+ pagesIncluded += await db().document.count({
1211
+ where: { collection: col.slug, deletedAt: null, status: 'PUBLISHED' },
1212
+ });
1213
+ }
1214
+ return json({
1215
+ data: {
1216
+ sitemapUrl: `${base}/sitemap.xml`,
1217
+ lastGeneratedAt: now,
1218
+ pagesIncluded,
1219
+ pagesExcluded: 0,
1220
+ autoRegenerateOnPublish: settings.autoRegenerateSitemapOnPublish,
1221
+ errors: [],
1222
+ warnings: [],
1223
+ },
1224
+ });
1225
+ }
1226
+ catch (err) {
1227
+ return internalError(err, 'seo/sitemap/regenerate');
1228
+ }
1229
+ });
1230
+ router.get('/seo/crawl-settings', async (request) => {
1231
+ try {
1232
+ const auth = await requireAuth(request);
1233
+ if (auth.error)
1234
+ return auth.error;
1235
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1236
+ if (roleErr)
1237
+ return roleErr;
1238
+ const { getSeoOverrides, resolveSeoModuleSettings } = await import('../../seo/config-store.js');
1239
+ const s = resolveSeoModuleSettings(await getSeoOverrides(db()));
1240
+ return json({
1241
+ data: {
1242
+ indexEntireSite: s.indexEntireSite,
1243
+ includeImagesInSitemap: s.includeImagesInSitemap,
1244
+ includePostsInSitemap: s.includePostsInSitemap,
1245
+ sitemapEnabled: s.sitemapEnabled,
1246
+ autoRegenerateSitemapOnPublish: s.autoRegenerateSitemapOnPublish,
1247
+ pingSearchEnginesOnPublish: s.pingSearchEnginesOnPublish,
1248
+ },
1249
+ });
1250
+ }
1251
+ catch (err) {
1252
+ return internalError(err, 'seo/crawl-settings GET');
1253
+ }
1254
+ });
1255
+ router.put('/seo/crawl-settings', async (request) => {
1256
+ try {
1257
+ const auth = await requireAuth(request);
1258
+ if (auth.error)
1259
+ return auth.error;
1260
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1261
+ if (roleErr)
1262
+ return roleErr;
1263
+ const body = (await request.json().catch(() => null));
1264
+ if (!body || typeof body !== 'object') {
1265
+ return errorResponse('Request body must be an object', 400);
1266
+ }
1267
+ const allowed = [
1268
+ 'indexEntireSite',
1269
+ 'includeImagesInSitemap',
1270
+ 'includePostsInSitemap',
1271
+ 'sitemapEnabled',
1272
+ 'autoRegenerateSitemapOnPublish',
1273
+ 'pingSearchEnginesOnPublish',
1274
+ ];
1275
+ const patch = {};
1276
+ for (const key of allowed) {
1277
+ if (typeof body[key] === 'boolean')
1278
+ patch[key] = body[key];
1279
+ }
1280
+ if (Object.keys(patch).length === 0) {
1281
+ return errorResponse('No valid crawl settings provided', 400);
1282
+ }
1283
+ // Snapshot current values so the audit trail records prev → new.
1284
+ const { getSeoOverrides, resolveSeoModuleSettings } = await import('../../seo/config-store.js');
1285
+ const { resolveSeoEnvironment } = await import('../../seo/robots.js');
1286
+ const before = resolveSeoModuleSettings(await getSeoOverrides(db()));
1287
+ await patchSeoModule(patch, auth.session.userId);
1288
+ try {
1289
+ const changedFields = Object.keys(patch).map((key) => ({
1290
+ field: key,
1291
+ from: before[key] ?? null,
1292
+ to: patch[key],
1293
+ }));
1294
+ await logEvent({
1295
+ event: 'update_seo_config',
1296
+ userId: auth.session.userId,
1297
+ details: {
1298
+ section: 'crawl-settings',
1299
+ changedFields,
1300
+ environment: resolveSeoEnvironment(),
1301
+ source: 'settings.seo',
1302
+ },
1303
+ });
1304
+ }
1305
+ catch {
1306
+ /* audit best-effort */
1307
+ }
1308
+ return json({ data: { ok: true } });
1309
+ }
1310
+ catch (err) {
1311
+ return internalError(err, 'seo/crawl-settings PUT');
1312
+ }
1313
+ });
1314
+ router.get('/seo/robots', async (request) => {
1315
+ try {
1316
+ const auth = await requireAuth(request);
1317
+ if (auth.error)
1318
+ return auth.error;
1319
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1320
+ if (roleErr)
1321
+ return roleErr;
1322
+ const { getSeoOverrides, resolveSeoModuleSettings } = await import('../../seo/config-store.js');
1323
+ const cfg = await loadEffectiveConfig();
1324
+ const settings = resolveSeoModuleSettings(await getSeoOverrides(db()));
1325
+ const custom = settings.robotsTxt?.trim();
1326
+ const body = custom ? settings.robotsTxt : buildDefaultRobots(request, cfg, settings);
1327
+ return json({ data: { body, generated: !custom } });
1328
+ }
1329
+ catch (err) {
1330
+ return internalError(err, 'seo/robots GET');
1331
+ }
1332
+ });
1333
+ router.put('/seo/robots', async (request) => {
1334
+ try {
1335
+ const auth = await requireAuth(request);
1336
+ if (auth.error)
1337
+ return auth.error;
1338
+ const roleErr = requireRole(auth.session.role, ADMIN_ROLES);
1339
+ if (roleErr)
1340
+ return roleErr;
1341
+ const body = (await request.json().catch(() => null));
1342
+ if (!body || typeof body.body !== 'string') {
1343
+ return errorResponse('`body` (string) is required', 400);
1344
+ }
1345
+ if (body.body.length > 50_000) {
1346
+ return errorResponse('robots.txt is too large (max 50KB)', 400);
1347
+ }
1348
+ await patchSeoModule({ robotsTxt: body.body }, auth.session.userId);
1349
+ try {
1350
+ await logEvent({
1351
+ event: 'update_seo_config',
1352
+ userId: auth.session.userId,
1353
+ details: { section: 'robots.txt' },
1354
+ });
1355
+ }
1356
+ catch {
1357
+ /* audit best-effort */
1358
+ }
1359
+ return json({ data: { ok: true } });
1360
+ }
1361
+ catch (err) {
1362
+ return internalError(err, 'seo/robots PUT');
1363
+ }
1364
+ });
1365
+ }
1366
+ //# sourceMappingURL=seo-public.js.map