ghost 6.53.0 → 6.54.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 (596) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-scheduling-0.1.1.tgz +0 -0
  4. package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
  5. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  6. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  7. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  8. package/components/tryghost-kg-converters-1.2.3.tgz +0 -0
  9. package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
  10. package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
  11. package/core/boot.js +9 -6
  12. package/core/built/admin/assets/Combination-CJG7Flp-.js +41 -0
  13. package/core/built/admin/assets/Growth-CSaHoSVD.js +3 -0
  14. package/core/built/admin/assets/Newsletters-C5cs6FGo.js +1 -0
  15. package/core/built/admin/assets/Overview-j4NaeUNm.js +1 -0
  16. package/core/built/admin/assets/{PolarAngleAxis-pciQ0MOy.js → PolarAngleAxis-BGjf7sBu.js} +1 -1
  17. package/core/built/admin/assets/{RadialBarChart-DWmw2PcX.js → RadialBarChart-zeFf9mBz.js} +1 -1
  18. package/core/built/admin/assets/Web-_fD935OX.js +2 -0
  19. package/core/built/admin/assets/account-migration-DLvVA5yq.js +1 -0
  20. package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-DHbZcxGM.js} +13 -13
  21. package/core/built/admin/assets/activitypub/activitypub.js +7 -7
  22. package/core/built/admin/assets/activitypub/{avatar-ZYco0ITb.js → avatar-B3DEDB1l.js} +10 -10
  23. package/core/built/admin/assets/activitypub/{avatar-flipboard-D541lc4F.js → avatar-flipboard-Cqrg0XMx.js} +3 -3
  24. package/core/built/admin/assets/activitypub/{bluesky-sharing-NOHUtHjl.js → bluesky-sharing-zfxUey_L.js} +38 -37
  25. package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-B-GOFDPZ.js → chunk-KS7C4IRE-D4HEcEwi.js} +716 -710
  26. package/core/built/admin/assets/activitypub/{content-formatters-bwrp4iEO.js → content-formatters-BpQARh28.js} +229 -181
  27. package/core/built/admin/assets/activitypub/{copy-C7m7ovHw.js → copy-D9UWIAan.js} +2 -2
  28. package/core/built/admin/assets/activitypub/{dist-B5ira32t.js → dist-Ba_QxHHl.js} +5 -5
  29. package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-CmwSZLHK.js} +33 -33
  30. package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-CXdwNmVG.js} +46 -45
  31. package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-DfbjzGM1.js} +20 -20
  32. package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-DSEBJOqf.js} +15 -15
  33. package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-CY7XVcx6.js} +13 -13
  34. package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
  36. package/core/built/admin/assets/activitypub/inbox-DtQ0kytT.js +1221 -0
  37. package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Dw96GQ7u.js} +6 -6
  38. package/core/built/admin/assets/activitypub/layout-IdVq3lRy.js +1 -0
  39. package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-Dg_-I-8C.js} +32 -31
  40. package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Cy1-uKMY.js} +21 -21
  41. package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-B_fvoLIM.js} +17 -17
  42. package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
  43. package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
  44. package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-ByJseZp6.js} +1607 -1606
  45. package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-BFtbnIjz.js} +264 -263
  46. package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
  47. package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-Dh3xXfce.js} +1311 -1295
  48. package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
  49. package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-DTgqJPxM.js} +14 -14
  50. package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-CdL9ZLqm.js} +10 -10
  51. package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
  52. package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
  53. package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
  54. package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-ogqwoBlb.js} +241 -237
  55. package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
  56. package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
  57. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
  58. package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-CxonteFD.js} +8 -8
  59. package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
  60. package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
  61. package/core/built/admin/assets/{audience-adiFehTD.js → audience-BKRdsFmy.js} +1 -1
  62. package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-Cn87L5Md.js} +1 -1
  63. package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
  64. package/core/built/admin/assets/automations-BP_aHamJ.js +1 -0
  65. package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
  66. package/core/built/admin/assets/bluesky-sharing-Bh36XPh4.js +1 -0
  67. package/core/built/admin/assets/box-BWbhXh21.js +1 -0
  68. package/core/built/admin/assets/breadcrumb-D34YWnaw.js +1 -0
  69. package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
  70. package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
  71. package/core/built/admin/assets/chart-helpers-DbklaJw9.js +1 -0
  72. package/core/built/admin/assets/checkbox-DA4-1UiI.js +1 -0
  73. package/core/built/admin/assets/chunk.524.45e0875f41b71e46e849.js +25 -0
  74. package/core/built/admin/assets/chunk.582.51defd4b009f0de8d4d5.js +27 -0
  75. package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.589.096f4d0bb775e5229aa9.js} +78 -85
  76. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.962.b73442b07be930bb5d85.js} +2216 -3188
  77. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.962.b73442b07be930bb5d85.js.LICENSE.txt} +0 -63
  78. package/core/built/admin/assets/code-editor-view-BKBrkffZ.js +1 -0
  79. package/core/built/admin/assets/comments-CzVNIT8b.js +1 -0
  80. package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
  81. package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
  82. package/core/built/admin/assets/date-range-select-B5vSsrpx.js +1 -0
  83. package/core/built/admin/assets/disabled-sources-indicator-NkOIoMue.js +1 -0
  84. package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
  85. package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
  86. package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
  87. package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
  88. package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
  89. package/core/built/admin/assets/domain-B7_n5nfx.js +1 -0
  90. package/core/built/admin/assets/dropzone-DcuJEEUf.js +5 -0
  91. package/core/built/admin/assets/edit-profile-rvDGrS8J.js +1 -0
  92. package/core/built/admin/assets/editor-BCiIyFjm.js +8 -0
  93. package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
  94. package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
  95. package/core/built/admin/assets/explore-BZAZOg5X.js +1 -0
  96. package/core/built/admin/assets/feed-CFV8xDw9.js +1 -0
  97. package/core/built/admin/assets/field-BW-M2Zwp.js +1 -0
  98. package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Fx8wiYYw.js} +1 -1
  99. package/core/built/admin/assets/filters-CGX_pf2N.js +1 -0
  100. package/core/built/admin/assets/filters-DtcXMZDU.js +1 -0
  101. package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
  102. package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-b1dce91ad3232cc259ee5fbbf9526243.js} +294 -290
  103. package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
  104. package/core/built/admin/assets/gift-link-modal-Bk8qpnMw.js +1 -0
  105. package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
  106. package/core/built/admin/assets/growth-Ck2s3JjR.js +1 -0
  107. package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
  108. package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-BRp1_aaC.js} +35 -35
  109. package/core/built/admin/assets/index-BBf502Wg.js +69 -0
  110. package/core/built/admin/assets/index-BCCZKxP2.css +1 -0
  111. package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
  112. package/core/built/admin/assets/input-group-DjuYnNCd.js +1 -0
  113. package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
  114. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
  115. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
  116. package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-CM7UFNdL.js} +2 -2
  117. package/core/built/admin/assets/kpi-card-BrGH6FsT.js +1 -0
  118. package/core/built/admin/assets/kpi-card-CIGyijjx.js +1 -0
  119. package/core/built/admin/assets/kpi-helpers-_HRRsklE.js +1 -0
  120. package/core/built/admin/assets/kpi-tabs-BSvh9eoq.js +1 -0
  121. package/core/built/admin/assets/label-BOR9XdKl.js +1 -0
  122. package/core/built/admin/assets/label-picker-BdNAWuUX.js +1 -0
  123. package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
  124. package/core/built/admin/assets/layout-Bw4GnxXp.js +1 -0
  125. package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
  126. package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
  127. package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
  128. package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
  129. package/core/built/admin/assets/member-custom-fields-DvFyamLu.js +1 -0
  130. package/core/built/admin/assets/member-detail-Cg2vTqvJ.js +1 -0
  131. package/core/built/admin/assets/members-DsPxYAVm.js +10 -0
  132. package/core/built/admin/assets/modals-Bf_fyvHZ.js +31 -0
  133. package/core/built/admin/assets/moderation-Dlp7M5sa.js +1 -0
  134. package/core/built/admin/assets/multi-select-combobox-CH1o8XXQ.js +1 -0
  135. package/core/built/admin/assets/newsletter-CQ5CAYUI.js +1 -0
  136. package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
  137. package/core/built/admin/assets/note-BrAZ7Z0o.js +1 -0
  138. package/core/built/admin/assets/notifications-BnbHLOPC.js +1 -0
  139. package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
  140. package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
  141. package/core/built/admin/assets/onboarding-route-eU146kuA.js +1 -0
  142. package/core/built/admin/assets/overview-BpbaK-xu.js +1 -0
  143. package/core/built/admin/assets/page-header-C0jVxtS8.js +1 -0
  144. package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
  145. package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
  146. package/core/built/admin/assets/post-analytics-Iw7dk1mT.js +1 -0
  147. package/core/built/admin/assets/post-analytics-header-D9pJ4iNm.js +1 -0
  148. package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BDqcfBor.js} +1 -1
  149. package/core/built/admin/assets/post-share-modal-DBfKl2GZ.js +1 -0
  150. package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
  151. package/core/built/admin/assets/preferences-D4EANGoc.js +5 -0
  152. package/core/built/admin/assets/profile-dJ44Bn_W.js +1 -0
  153. package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
  154. package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
  155. package/core/built/admin/assets/select--2uVN9_-.js +1 -0
  156. package/core/built/admin/assets/settings-Bz3RZRmE.js +1 -0
  157. package/core/built/admin/assets/settings-SD9bxIpt.js +4 -0
  158. package/core/built/admin/assets/share-modal-CkdTTMJd.js +1 -0
  159. package/core/built/admin/assets/social-urls-BvFZwYcE.js +8 -0
  160. package/core/built/admin/assets/sort-button-DZp9Y2r1.js +1 -0
  161. package/core/built/admin/assets/source-icon-CHr9qJ2Y.js +1 -0
  162. package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
  163. package/core/built/admin/assets/stats-DGoXZxWE.js +1 -0
  164. package/core/built/admin/assets/stats-view-D2-1L0ms.js +1 -0
  165. package/core/built/admin/assets/step-1-RdahbwyG.js +1 -0
  166. package/core/built/admin/assets/step-2-D83PeRwd.js +1 -0
  167. package/core/built/admin/assets/step-3-p_Op4wv4.js +2 -0
  168. package/core/built/admin/assets/switch-qp518gFQ.js +1 -0
  169. package/core/built/admin/assets/table-B8LgTQJZ.js +1 -0
  170. package/core/built/admin/assets/tabs-D3ZOYkM7.js +1 -0
  171. package/core/built/admin/assets/tags-B4l891z2.js +1 -0
  172. package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
  173. package/core/built/admin/assets/textarea-CTlb3Uu6.js +1 -0
  174. package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
  175. package/core/built/admin/assets/toggle-group-DNXDkAwf.js +1 -0
  176. package/core/built/admin/assets/topic-filter-DZGjEcz3.js +1 -0
  177. package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-CaT8RirX.js} +1 -1
  178. package/core/built/admin/assets/use-filter-params-DeQ8sX4N.js +1 -0
  179. package/core/built/admin/assets/use-growth-stats-9Db2CuJe.js +1 -0
  180. package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-BV54YcQS.js} +1 -1
  181. package/core/built/admin/assets/use-reply-chain-data-DuYZGDan.js +1 -0
  182. package/core/built/admin/assets/use-simple-pagination-8fTua9Nt.js +1 -0
  183. package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-Dz156HvZ.js} +1 -1
  184. package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-C9RUdL_n.js} +1 -1
  185. package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
  186. package/core/built/admin/assets/virtual-list-BCvP0YF-.js +1 -0
  187. package/core/built/admin/assets/web-DTZnnUGr.js +1 -0
  188. package/core/built/admin/index.html +18 -22
  189. package/core/frontend/apps/private-blogging/index.js +1 -1
  190. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  191. package/core/frontend/helpers/split.js +2 -1
  192. package/core/frontend/meta/asset-url.js +1 -1
  193. package/core/frontend/meta/author-image.js +1 -1
  194. package/core/frontend/meta/blog-logo.js +1 -1
  195. package/core/frontend/meta/canonical-url.js +1 -1
  196. package/core/frontend/meta/cover-image.js +1 -1
  197. package/core/frontend/meta/get-meta.js +1 -1
  198. package/core/frontend/meta/og-image.js +1 -1
  199. package/core/frontend/meta/paginated-url.js +1 -1
  200. package/core/frontend/meta/twitter-image.js +1 -1
  201. package/core/frontend/meta/url.js +1 -1
  202. package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
  203. package/core/frontend/services/llms/handler.js +1 -1
  204. package/core/frontend/services/proxy.js +31 -2
  205. package/core/frontend/services/routing/collection-router.js +1 -1
  206. package/core/frontend/services/routing/controllers/email-post.js +1 -1
  207. package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
  208. package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
  209. package/core/frontend/services/routing/controllers/entry.js +1 -1
  210. package/core/frontend/services/routing/controllers/entry.ts +1 -1
  211. package/core/frontend/services/routing/controllers/previews.js +6 -7
  212. package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
  213. package/core/frontend/services/routing/email-router.js +1 -1
  214. package/core/frontend/services/routing/events.js +12 -0
  215. package/core/frontend/services/routing/middleware/page-param.js +1 -1
  216. package/core/frontend/services/routing/parent-router.js +1 -1
  217. package/core/frontend/services/routing/preview-router.js +1 -1
  218. package/core/frontend/services/routing/router-manager.js +4 -8
  219. package/core/frontend/services/routing/rss-router.js +1 -1
  220. package/core/frontend/services/routing/static-pages-router.js +1 -1
  221. package/core/frontend/services/routing/static-routes-router.js +1 -1
  222. package/core/frontend/services/routing/taxonomy-router.js +1 -1
  223. package/core/frontend/services/rss/generate-feed.js +1 -1
  224. package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
  225. package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
  226. package/core/frontend/services/sitemap/site-map-manager.js +14 -8
  227. package/core/frontend/services/sitemap/utils.js +1 -1
  228. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
  229. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
  230. package/core/frontend/utils/images.js +1 -1
  231. package/core/frontend/web/middleware/admin-toolbar.js +1 -1
  232. package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
  233. package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
  234. package/core/frontend/web/routers/serve-favicon.js +1 -1
  235. package/core/frontend/web/routers/serve-public-file.js +1 -1
  236. package/core/frontend/web/site.js +5 -5
  237. package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
  238. package/core/server/adapters/cache/MemoryCache.js +2 -2
  239. package/core/server/adapters/cache/Redis.js +1 -1
  240. package/core/server/adapters/cache/index.js +1 -1
  241. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
  242. package/core/server/adapters/route-settings/FileStore.js +2 -8
  243. package/core/server/adapters/route-settings/FileStore.ts +1 -6
  244. package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
  245. package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
  246. package/core/server/adapters/route-settings/utils.js +13 -0
  247. package/core/server/adapters/route-settings/utils.ts +7 -0
  248. package/core/server/adapters/scheduling/deps.d.ts +0 -2
  249. package/core/server/adapters/scheduling/error-capture.js +76 -0
  250. package/core/server/adapters/scheduling/error-capture.ts +91 -0
  251. package/core/server/adapters/scheduling/utils.js +18 -34
  252. package/core/server/adapters/scheduling/utils.ts +36 -0
  253. package/core/server/adapters/storage/LocalFilesStorage.js +1 -1
  254. package/core/server/adapters/storage/LocalImagesStorage.js +1 -1
  255. package/core/server/adapters/storage/LocalMediaStorage.js +1 -1
  256. package/core/server/adapters/storage/LocalStorageBase.js +3 -3
  257. package/core/server/adapters/storage/S3Storage.js +2 -2
  258. package/core/server/adapters/storage/S3Storage.ts +1 -1
  259. package/core/server/adapters/storage/utils.js +1 -1
  260. package/core/server/api/endpoints/authentication.js +1 -1
  261. package/core/server/api/endpoints/featurebase.js +1 -1
  262. package/core/server/api/endpoints/files.js +2 -2
  263. package/core/server/api/endpoints/images.js +2 -2
  264. package/core/server/api/endpoints/libraries.d.ts +0 -1
  265. package/core/server/api/endpoints/media.js +8 -5
  266. package/core/server/api/endpoints/member-custom-fields.js +4 -1
  267. package/core/server/api/endpoints/member-custom-fields.ts +4 -1
  268. package/core/server/api/endpoints/posts.js +17 -1
  269. package/core/server/api/endpoints/search-index-public.js +4 -3
  270. package/core/server/api/endpoints/search-index.js +5 -4
  271. package/core/server/api/endpoints/settings-public.js +1 -1
  272. package/core/server/api/endpoints/settings.js +3 -1
  273. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
  274. package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
  275. package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
  276. package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
  277. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
  278. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
  279. package/core/server/api/endpoints/utils/serializers/output/members.js +16 -26
  280. package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
  281. package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
  282. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
  283. package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
  284. package/core/server/data/db/backup.js +1 -1
  285. package/core/server/data/importer/handlers/image.js +3 -3
  286. package/core/server/data/importer/import-manager.js +6 -4
  287. package/core/server/data/importer/importers/content-file-importer.js +2 -2
  288. package/core/server/data/migrations/utils/schema.js +4 -2
  289. package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
  290. package/core/server/data/migrations/versions/6.54/2026-07-20-13-59-21-drop-email-tracked-sent-count-from-automation-action-revisions.js +7 -0
  291. package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
  292. package/core/server/data/migrations/versions/6.54/2026-07-21-21-08-15-add-automated-email-recipients-mailgun-message-id-index.js +3 -0
  293. package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
  294. package/core/server/data/migrations/versions/6.54/2026-07-22-15-10-30-add-email-clicked-count-to-automation-action-revisions.js +7 -0
  295. package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
  296. package/core/server/data/schema/commands.js +37 -3
  297. package/core/server/data/schema/fixtures/fixtures.json +7 -0
  298. package/core/server/data/schema/lib/default-index-name.js +20 -0
  299. package/core/server/data/schema/schema.js +40 -17
  300. package/core/server/data/seeders/data-generator.js +4 -2
  301. package/core/server/lib/image/image-size.js +5 -7
  302. package/core/server/lib/image/image-utils.js +2 -2
  303. package/core/server/lib/image/index.js +4 -4
  304. package/core/server/lib/lexical.js +3 -3
  305. package/core/server/lib/mobiledoc.js +2 -2
  306. package/core/server/lib/validate-password.js +1 -1
  307. package/core/server/models/action.js +9 -0
  308. package/core/server/models/base/plugins/generate-slug.js +1 -1
  309. package/core/server/models/collection.js +1 -1
  310. package/core/server/models/custom-theme-setting.js +1 -1
  311. package/core/server/models/member.js +73 -0
  312. package/core/server/models/newsletter.js +1 -1
  313. package/core/server/models/post.js +19 -5
  314. package/core/server/models/posts-meta.js +1 -1
  315. package/core/server/models/redirect.js +1 -1
  316. package/core/server/models/settings.js +1 -1
  317. package/core/server/models/snippet.js +1 -1
  318. package/core/server/models/tag.js +1 -1
  319. package/core/server/models/user.js +1 -1
  320. package/core/server/models/welcome-email-automated-email.js +1 -1
  321. package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
  322. package/core/server/services/adapter-manager/adapter-manager.js +5 -1
  323. package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
  324. package/core/server/services/adapter-manager/index.js +18 -15
  325. package/core/server/services/adapter-manager/index.ts +23 -17
  326. package/core/server/services/adapter-manager/utils.js +124 -14
  327. package/core/server/services/adapter-manager/utils.ts +130 -14
  328. package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
  329. package/core/server/services/audience-feedback/index.js +1 -1
  330. package/core/server/services/auth/passwordreset.js +1 -1
  331. package/core/server/services/auth/session/express-session.js +1 -1
  332. package/core/server/services/auth/session/index.js +2 -2
  333. package/core/server/services/auth/session/session-service.js +1 -1
  334. package/core/server/services/automations/automations-api.js +2 -19
  335. package/core/server/services/automations/automations-api.ts +2 -31
  336. package/core/server/services/automations/automations-repository.ts +15 -0
  337. package/core/server/services/automations/database-automations-repository.js +30 -2
  338. package/core/server/services/automations/database-automations-repository.ts +33 -2
  339. package/core/server/services/automations/poll.js +16 -12
  340. package/core/server/services/automations/poll.ts +17 -15
  341. package/core/server/services/automations/service.js +1 -1
  342. package/core/server/services/automations/service.ts +3 -13
  343. package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
  344. package/core/server/services/comments/index.js +1 -1
  345. package/core/server/services/custom-redirects/index.js +2 -2
  346. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
  347. package/core/server/services/email-analytics/email-analytics-service.js +1 -1
  348. package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
  349. package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
  350. package/core/server/services/email-analytics/index.js +2 -3
  351. package/core/server/services/email-analytics/index.ts +1 -2
  352. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
  353. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
  354. package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
  355. package/core/server/services/email-analytics/jobs/index.js +0 -2
  356. package/core/server/services/email-service/email-service-wrapper.js +1 -1
  357. package/core/server/services/email-service/email-service.js +20 -4
  358. package/core/server/services/explore-ping/explore-ping-service.js +24 -39
  359. package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
  360. package/core/server/services/explore-ping/index.js +11 -11
  361. package/core/server/services/explore-ping/index.ts +42 -0
  362. package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
  363. package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
  364. package/core/server/services/gifts/gift-service-wrapper.js +1 -1
  365. package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
  366. package/core/server/services/indexnow-ping/constants.js +30 -0
  367. package/core/server/services/indexnow-ping/constants.ts +32 -0
  368. package/core/server/services/indexnow-ping/index.js +29 -253
  369. package/core/server/services/indexnow-ping/index.ts +37 -0
  370. package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
  371. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
  372. package/core/server/services/invites/index.js +1 -1
  373. package/core/server/services/lib/mailgun-client.js +3 -3
  374. package/core/server/services/link-redirection/index.js +2 -2
  375. package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
  376. package/core/server/services/link-redirection/link-redirect.js +12 -13
  377. package/core/server/services/link-redirection/link-redirect.ts +22 -0
  378. package/core/server/services/link-redirection/link-redirects-service.js +1 -1
  379. package/core/server/services/link-tracking/full-post-link.js +2 -2
  380. package/core/server/services/link-tracking/index.js +1 -1
  381. package/core/server/services/mail/ghost-mailer.js +1 -1
  382. package/core/server/services/mail/index.js +1 -1
  383. package/core/server/services/media-inliner/external-media-inliner.js +2 -2
  384. package/core/server/services/media-inliner/service.js +4 -3
  385. package/core/server/services/member-attribution/index.js +1 -1
  386. package/core/server/services/member-welcome-emails/service.js +1 -1
  387. package/core/server/services/members/api.js +8 -2
  388. package/core/server/services/members/csv/index.js +10 -0
  389. package/core/server/services/members/csv/index.ts +3 -0
  390. package/core/server/services/members/csv/parse.js +94 -0
  391. package/core/server/services/members/csv/parse.ts +111 -0
  392. package/core/server/services/members/csv/types.js +2 -0
  393. package/core/server/services/members/csv/types.ts +39 -0
  394. package/core/server/services/members/csv/unparse.js +69 -0
  395. package/core/server/services/members/csv/unparse.ts +79 -0
  396. package/core/server/services/members/exporter/query.js +35 -8
  397. package/core/server/services/members/importer/config.js +35 -0
  398. package/core/server/services/members/importer/config.ts +39 -0
  399. package/core/server/services/members/importer/members-csv-importer.js +31 -13
  400. package/core/server/services/members/members-api/members-api.js +4 -2
  401. package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
  402. package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
  403. package/core/server/services/members/middleware.js +1 -1
  404. package/core/server/services/members/service.js +15 -2
  405. package/core/server/services/members/stripe-connect.js +1 -1
  406. package/core/server/services/members-custom-fields/actions.js +3 -0
  407. package/core/server/services/members-custom-fields/actions.ts +6 -2
  408. package/core/server/services/members-custom-fields/config.js +34 -0
  409. package/core/server/services/members-custom-fields/config.ts +38 -0
  410. package/core/server/services/members-custom-fields/definitions-service.js +156 -21
  411. package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
  412. package/core/server/services/members-custom-fields/index.js +16 -3
  413. package/core/server/services/members-custom-fields/index.ts +17 -3
  414. package/core/server/services/members-custom-fields/values-service.js +56 -10
  415. package/core/server/services/members-custom-fields/values-service.ts +62 -10
  416. package/core/server/services/mentions/mention-sending-service.js +22 -2
  417. package/core/server/services/mentions/service.js +21 -5
  418. package/core/server/services/newsletters/index.js +1 -1
  419. package/core/server/services/oembed/oembed-service.js +122 -33
  420. package/core/server/services/oembed/service.js +4 -2
  421. package/core/server/services/offers/service.js +1 -1
  422. package/core/server/services/post-scheduling/index.js +4 -3
  423. package/core/server/services/post-scheduling/index.ts +4 -3
  424. package/core/server/services/post-scheduling/post-scheduling.js +1 -1
  425. package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
  426. package/core/server/services/posts/post-email-handler.js +13 -6
  427. package/core/server/services/posts/post-scheduling.js +1 -1
  428. package/core/server/services/posts/posts-service-instance.js +1 -1
  429. package/core/server/services/posts/posts-service.js +2 -2
  430. package/core/server/services/posts-public/service.js +1 -1
  431. package/core/server/services/public-config/site.js +1 -1
  432. package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
  433. package/core/server/services/recommendations/service/libraries.d.ts +0 -2
  434. package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
  435. package/core/server/services/route-settings/index.js +1 -1
  436. package/core/server/services/route-settings/route-settings-parser.js +134 -124
  437. package/core/server/services/route-settings/route-settings-parser.ts +160 -125
  438. package/core/server/services/route-settings/validation-errors.js +178 -0
  439. package/core/server/services/route-settings/validation-errors.ts +196 -0
  440. package/core/server/services/settings/settings-service.js +2 -2
  441. package/core/server/services/settings-helpers/index.js +1 -1
  442. package/core/server/services/slack-notifications/service.js +1 -1
  443. package/core/server/services/slack-ping/constants.js +16 -0
  444. package/core/server/services/slack-ping/constants.ts +15 -0
  445. package/core/server/services/slack-ping/index.js +26 -204
  446. package/core/server/services/slack-ping/index.ts +35 -0
  447. package/core/server/services/slack-ping/slack-ping-service.js +214 -0
  448. package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
  449. package/core/server/services/staff/index.js +1 -1
  450. package/core/server/services/stats/posts-stats-service.js +1 -1
  451. package/core/server/services/stats/service.js +1 -1
  452. package/core/server/services/stripe/service.js +1 -1
  453. package/core/server/services/tags-public/service.js +1 -1
  454. package/core/server/services/themes/validate.js +1 -1
  455. package/core/server/services/update-check/index.js +1 -1
  456. package/core/server/services/url/lazy-url-service.js +66 -6
  457. package/core/server/services/url/lazy-url-service.ts +73 -6
  458. package/core/server/services/url/url-generator.js +1 -1
  459. package/core/server/services/url/url-service-facade.js +68 -3
  460. package/core/server/services/url/url-service-facade.ts +79 -4
  461. package/core/server/services/url/url-service.js +1 -1
  462. package/core/server/services/url/urls.js +1 -1
  463. package/core/server/services/webhooks/index.js +19 -2
  464. package/core/server/services/webhooks/listen.js +6 -11
  465. package/core/server/services/webhooks/payload.js +1 -3
  466. package/core/server/services/webhooks/serialize.js +16 -1
  467. package/core/server/web/admin/app.js +1 -1
  468. package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
  469. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  470. package/core/server/web/api/middleware/cors.js +1 -1
  471. package/core/server/web/api/middleware/upload.js +4 -0
  472. package/core/server/web/gift-preview/controller.js +1 -1
  473. package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
  474. package/core/server/web/shared/middleware/uncapitalise.js +2 -2
  475. package/core/server/web/shared/middleware/url-redirects.js +1 -1
  476. package/core/shared/config/defaults.json +8 -1
  477. package/core/shared/config/overrides.json +4 -0
  478. package/core/shared/url-utils.js +19 -15
  479. package/core/shared/url-utils.ts +20 -0
  480. package/ghost.js +0 -1
  481. package/package.json +26 -31
  482. package/pnpm-lock.yaml +681 -2789
  483. package/pnpm-workspace.yaml +31 -17
  484. package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
  485. package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
  486. package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
  487. package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
  488. package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
  489. package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
  490. package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
  491. package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
  492. package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
  493. package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
  494. package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
  495. package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
  496. package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
  497. package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
  498. package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
  499. package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
  500. package/core/built/admin/assets/button--i2uMDDn.js +0 -4
  501. package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
  502. package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
  503. package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
  504. package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
  505. package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
  506. package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
  507. package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
  508. package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
  509. package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
  510. package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
  511. package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
  512. package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
  513. package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
  514. package/core/built/admin/assets/dist-DJ6c4_De.js +0 -1
  515. package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
  516. package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
  517. package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
  518. package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
  519. package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
  520. package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
  521. package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
  522. package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
  523. package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
  524. package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
  525. package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
  526. package/core/built/admin/assets/feed-C58p2voG.js +0 -1
  527. package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
  528. package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
  529. package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
  530. package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
  531. package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
  532. package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
  533. package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
  534. package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
  535. package/core/built/admin/assets/index-BacwlcOy.js +0 -67
  536. package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
  537. package/core/built/admin/assets/inline-C22rnPro.js +0 -1
  538. package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
  539. package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
  540. package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
  541. package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
  542. package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
  543. package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
  544. package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
  545. package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
  546. package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
  547. package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
  548. package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
  549. package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
  550. package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
  551. package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
  552. package/core/built/admin/assets/members-CUWD9jal.js +0 -10
  553. package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
  554. package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
  555. package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
  556. package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
  557. package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
  558. package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
  559. package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
  560. package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
  561. package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
  562. package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
  563. package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
  564. package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
  565. package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
  566. package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
  567. package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
  568. package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
  569. package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
  570. package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
  571. package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
  572. package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
  573. package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
  574. package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
  575. package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
  576. package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
  577. package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
  578. package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
  579. package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
  580. package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
  581. package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
  582. package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
  583. package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
  584. package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
  585. package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
  586. package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
  587. package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
  588. package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
  589. package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
  590. package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
  591. package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
  592. package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
  593. package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
  594. package/core/server/adapters/scheduling/scheduling-base.js +0 -5
  595. package/core/server/adapters/sso/SSOBase.js +0 -5
  596. package/core/server/adapters/storage/index.js +0 -17
@@ -6,7 +6,7 @@ import type {InternalApiKey, InternalKeys} from '../internal-keys';
6
6
  // CJS-only modules — typed loosely below. models is the Bookshelf registry
7
7
  // without TS declarations; the rest are JS modules without types.
8
8
  const models = require('../../models');
9
- const urlUtils = require('../../../shared/url-utils');
9
+ const urlUtils = require('../../../shared/url-utils').default;
10
10
  const {getSignedAdminToken} = require('../../adapters/scheduling/utils');
11
11
  const events = require('../../lib/common/events');
12
12
 
@@ -22,13 +22,13 @@ class PostEmailHandler {
22
22
  * Validates email can be sent before saving the post (if an email will be sent)
23
23
  *
24
24
  * @param {import('@tryghost/api-framework').Frame} frame
25
- * @returns {Promise<void>}
25
+ * @returns {Promise<{newsletter: Object, emailRecipientFilter: string, emailCount: number}|null>}
26
26
  */
27
27
  async validateBeforeSave(frame) {
28
28
  const newStatus = frame.data.posts[0].status;
29
29
 
30
30
  if (!EMAIL_SENDING_STATUSES.includes(newStatus)) {
31
- return;
31
+ return null;
32
32
  }
33
33
 
34
34
  const existingPost = await this.models.Post.findOne(
@@ -41,7 +41,7 @@ class PostEmailHandler {
41
41
  const sendingEmail = hasNewsletter && this.shouldSendEmail(newStatus, previousStatus);
42
42
 
43
43
  if (!sendingEmail) {
44
- return;
44
+ return null;
45
45
  }
46
46
 
47
47
  const emailRecipientFilter = frame.options.email_segment || existingPost?.get('email_recipient_filter') || 'all';
@@ -50,7 +50,9 @@ class PostEmailHandler {
50
50
 
51
51
  const newsletter = await this.getNewsletter(frame, existingPost);
52
52
 
53
- await this.emailService.checkCanSendEmail(newsletter, emailRecipientFilter);
53
+ const {emailCount} = await this.emailService.checkCanSendEmail(newsletter, emailRecipientFilter);
54
+
55
+ return {newsletter, emailRecipientFilter, emailCount};
54
56
  }
55
57
 
56
58
  /**
@@ -97,9 +99,14 @@ class PostEmailHandler {
97
99
  * Handles creating or retrying the newsletter email after post is saved
98
100
  *
99
101
  * @param {Object} model - The post model
102
+ * @param {Object} [options]
103
+ * @param {Object} [options.preflight] - Validation result from validateBeforeSave, passed through to createEmail
104
+ * @param {Object} [options.preflight.newsletter]
105
+ * @param {string} [options.preflight.emailRecipientFilter]
106
+ * @param {number} [options.preflight.emailCount]
100
107
  * @returns {Promise<void>}
101
108
  */
102
- async createOrRetryEmail(model) {
109
+ async createOrRetryEmail(model, {preflight} = {}) {
103
110
  if (!model.get('newsletter_id')) {
104
111
  return;
105
112
  }
@@ -114,7 +121,7 @@ class PostEmailHandler {
114
121
  let email;
115
122
 
116
123
  if (!postEmail) {
117
- email = await this.emailService.createEmail(model);
124
+ email = await this.emailService.createEmail(model, {preflight});
118
125
  } else if (postEmail.get('status') === 'failed') {
119
126
  email = await this.emailService.retryEmail(postEmail);
120
127
  }
@@ -2,7 +2,7 @@ const _ = require('lodash');
2
2
  const errors = require('@tryghost/errors');
3
3
  const moment = require('moment');
4
4
  const config = require('../../../shared/config');
5
- const urlUtils = require('../../../shared/url-utils');
5
+ const urlUtils = require('../../../shared/url-utils').default;
6
6
  const api = require('../../api').endpoints;
7
7
 
8
8
  const messages = {
@@ -6,7 +6,7 @@ const url = require('../../../server/api/endpoints/utils/serializers/output/util
6
6
  * @returns {InstanceType<PostsService>} instance of the PostsService
7
7
  */
8
8
  const getPostServiceInstance = () => {
9
- const urlUtils = require('../../../shared/url-utils');
9
+ const urlUtils = require('../../../shared/url-utils').default;
10
10
  const labs = require('../../../shared/labs');
11
11
  const models = require('../../models');
12
12
  const PostStats = require('./stats/post-stats');
@@ -61,11 +61,11 @@ class PostsService {
61
61
  * @returns
62
62
  */
63
63
  async editPost(frame, options) {
64
- await this.postEmailHandler.validateBeforeSave(frame);
64
+ const preflight = await this.postEmailHandler.validateBeforeSave(frame);
65
65
 
66
66
  const model = await this.models.Post.edit(frame.data.posts[0], frame.options);
67
67
 
68
- await this.postEmailHandler.createOrRetryEmail(model);
68
+ await this.postEmailHandler.createOrRetryEmail(model, {preflight});
69
69
 
70
70
  const dto = model.toJSON(frame.options);
71
71
 
@@ -6,7 +6,7 @@ class PostsPublicServiceWrapper {
6
6
  }
7
7
 
8
8
  // Wire up all the dependencies
9
- const adapterManager = require('../adapter-manager');
9
+ const adapterManager = require('../adapter-manager').default;
10
10
  const config = require('../../../shared/config');
11
11
  const EventRegistry = require('../../lib/common/events');
12
12
 
@@ -1,7 +1,7 @@
1
1
  const ghostVersion = require('@tryghost/version');
2
2
  const settingsCache = require('../../../shared/settings-cache');
3
3
  const config = require('../../../shared/config');
4
- const urlUtils = require('../../../shared/url-utils');
4
+ const urlUtils = require('../../../shared/url-utils').default;
5
5
 
6
6
  module.exports = function getSiteProperties() {
7
7
  const siteProperties = {
@@ -49,7 +49,7 @@ class RecommendationServiceWrapper {
49
49
  return;
50
50
  }
51
51
 
52
- const urlUtils = require('../../../shared/url-utils');
52
+ const urlUtils = require('../../../shared/url-utils').default;
53
53
  const models = require('../../models');
54
54
  const sentry = require('../../../shared/sentry');
55
55
  const settings = require('../settings');
@@ -1,4 +1,2 @@
1
- declare module '@tryghost/tpl';
2
- declare module '@tryghost/logging';
3
1
  declare module '@tryghost/mongo-utils';
4
2
  declare module '@tryghost/nql';
@@ -112,7 +112,7 @@ class DynamicRoutingService {
112
112
  }
113
113
  }
114
114
 
115
- async upload(filePath) {
115
+ async upload(yamlContent) {
116
116
  const parseYaml = require('./yaml-parser');
117
117
  const {parseRouteSettings} = require('./route-settings-parser');
118
118
  const urlService = require('../url');
@@ -120,8 +120,7 @@ class DynamicRoutingService {
120
120
 
121
121
  // Parse and validate before anything is persisted — an invalid
122
122
  // upload is rejected here and never reaches the store.
123
- const content = await fs.readFile(filePath, 'utf8');
124
- const next = parseRouteSettings(parseYaml(content), content);
123
+ const next = parseRouteSettings(parseYaml(yamlContent), yamlContent);
125
124
  let previous = null;
126
125
  try {
127
126
  previous = await this.store.get();
@@ -6,7 +6,7 @@ const service = new DynamicRoutingService();
6
6
 
7
7
  module.exports = {
8
8
  init: async () => {
9
- const adapterManager = require('../adapter-manager');
9
+ const adapterManager = require('../adapter-manager').default;
10
10
  const SettingsLoader = require('./settings-loader');
11
11
  const SettingsPathManager = require('./settings-path-manager');
12
12
 
@@ -7,37 +7,46 @@ exports.parseRouteSettings = parseRouteSettings;
7
7
  exports.serializeRouteSettings = serializeRouteSettings;
8
8
  const js_yaml_1 = __importDefault(require("js-yaml"));
9
9
  const zod_1 = require("zod");
10
- const errors_1 = __importDefault(require("@tryghost/errors"));
11
10
  const tpl_1 = __importDefault(require("@tryghost/tpl"));
11
+ const validation_errors_1 = require("./validation-errors");
12
12
  const messages = {
13
- validationError: 'The following definition "{at}" is invalid: {reason}',
14
- badDataError: 'Please wrap the data definition into a custom name.',
13
+ badDataError: '"{key}" is a reserved key. Please wrap the data definition into a custom name.',
15
14
  badDataHelp: 'Example:\n data:\n my-tag:\n resource: tags\n ...\n',
16
- authorDeprecatedError: 'Please choose a different name. We recommend not using author.'
15
+ authorDeprecatedError: '"author" is reserved. Please choose a different name. We recommend not using author.'
17
16
  };
18
- function validationError(at, reason, help) {
19
- return new errors_1.default.ValidationError({
20
- message: (0, tpl_1.default)(messages.validationError, { at, reason }),
21
- ...(help ? { help } : {})
22
- });
23
- }
24
17
  const VALID_SHORTFORM_RESOURCES = ['tag', 'page', 'post', 'author'];
25
18
  const VALID_LONGFORM_RESOURCES = ['tags', 'posts', 'pages', 'authors'];
26
19
  const RESERVED_DATA_KEYS = ['resource', 'type', 'limit', 'order', 'include', 'filter', 'status', 'visibility', 'slug', 'redirect'];
27
- const DataShortFormSchema = zod_1.z.string().superRefine((v, ctx) => {
28
- if (!/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_-]+$/.test(v)) {
29
- ctx.addIssue({ code: 'custom', message: (0, tpl_1.default)(messages.validationError, { at: v, reason: 'Incorrect Format. Please use e.g. tag.recipes' }) });
30
- return;
20
+ // YAML parses a bare `filter:` as null and authors commonly quote numeric scalars
21
+ // (`limit: "100"`); the legacy validator accepted both, so treat an explicitly empty
22
+ // value as unset and coerce digit-only limit strings to numbers.
23
+ const OptionalStringField = zod_1.z.string().nullish().transform(v => v ?? undefined);
24
+ const OptionalBooleanField = zod_1.z.boolean().nullish().transform(v => v ?? undefined);
25
+ const LimitField = zod_1.z.union([zod_1.z.number(), zod_1.z.literal('all'), zod_1.z.string().regex(/^\d+$/).transform(Number)])
26
+ .nullish().transform(v => v ?? undefined);
27
+ const SHORTFORM_HELP = 'e.g. data: tag.recipes';
28
+ /**
29
+ * Shorthand data definitions look like `tag.recipes` — resource, dot, slug.
30
+ *
31
+ * `%s` stands in for the slug: on channel routes and collections, fetch-data
32
+ * substitutes it with the request's `slug` param at query time, which is how a
33
+ * wildcard route such as `/author/:slug/` serves a different author per request.
34
+ * There is no static slug that could replace it, so rejecting it would break
35
+ * those routes.
36
+ */
37
+ function validateDataShortForm(value, path) {
38
+ if (!/^[a-zA-Z0-9_]+\.(?:%s|[a-zA-Z0-9_-]+)$/.test(value)) {
39
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `"${value}" is not a valid data shorthand. Please use resource.slug, e.g. tag.recipes.`, SHORTFORM_HELP);
31
40
  }
32
- const resource = v.split('.')[0];
41
+ const resource = value.split('.')[0];
33
42
  if (!VALID_SHORTFORM_RESOURCES.includes(resource)) {
34
- ctx.addIssue({ code: 'custom', message: (0, tpl_1.default)(messages.validationError, { at: v, reason: `${resource} not supported. Please use ${VALID_SHORTFORM_RESOURCES.join(', ')}.` }) });
43
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `resource "${resource}" is not supported. Please use ${(0, validation_errors_1.humanList)(VALID_SHORTFORM_RESOURCES)}.`, SHORTFORM_HELP);
35
44
  }
36
- });
45
+ }
37
46
  const DataReadEntrySchema = zod_1.z.object({
38
47
  type: zod_1.z.literal('read'),
39
48
  resource: zod_1.z.enum(VALID_LONGFORM_RESOURCES),
40
- slug: zod_1.z.string({ message: 'slug is required for read data entries.' }).min(1, { message: 'slug is required for read data entries.' }),
49
+ slug: zod_1.z.string().min(1),
41
50
  redirect: zod_1.z.boolean().optional(),
42
51
  include: zod_1.z.string().optional(),
43
52
  visibility: zod_1.z.string().optional(),
@@ -46,98 +55,104 @@ const DataReadEntrySchema = zod_1.z.object({
46
55
  const DataBrowseEntrySchema = zod_1.z.object({
47
56
  type: zod_1.z.literal('browse'),
48
57
  resource: zod_1.z.enum(VALID_LONGFORM_RESOURCES),
49
- filter: zod_1.z.string().optional(),
50
- limit: zod_1.z.union([zod_1.z.number(), zod_1.z.literal('all')]).optional(),
51
- order: zod_1.z.string().optional(),
52
- include: zod_1.z.string().optional(),
53
- fields: zod_1.z.string().optional(),
54
- visibility: zod_1.z.string().optional(),
55
- status: zod_1.z.string().optional(),
58
+ filter: OptionalStringField,
59
+ limit: LimitField,
60
+ order: OptionalStringField,
61
+ include: OptionalStringField,
62
+ fields: OptionalStringField,
63
+ visibility: OptionalStringField,
64
+ status: OptionalStringField,
56
65
  page: zod_1.z.number().optional()
57
66
  });
58
67
  const DataLongFormEntrySchema = zod_1.z.discriminatedUnion('type', [DataReadEntrySchema, DataBrowseEntrySchema]);
59
- function parseDataEntry(key, value) {
68
+ const DATA_ENTRY_HELP = 'e.g.\n data:\n my-tag:\n resource: tags\n type: read\n slug: recipes\n';
69
+ function parseDataEntry(value, path) {
60
70
  if (typeof value === 'string') {
61
- const result = DataShortFormSchema.safeParse(value);
62
- if (!result.success) {
63
- throw toValidationError(result.error);
64
- }
71
+ validateDataShortForm(value, path);
65
72
  return value;
66
73
  }
67
- if (typeof value === 'object' && value !== null) {
74
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
68
75
  const result = DataLongFormEntrySchema.safeParse(value);
69
76
  if (!result.success) {
70
77
  const issue = result.error.issues[0];
71
- if (issue.message.includes('discriminator')) {
72
- const typeVal = value.type;
73
- if (typeVal === undefined) {
74
- throw validationError(JSON.stringify(value), 'type is required.');
78
+ const at = (0, validation_errors_1.formatLocation)(path);
79
+ const record = value;
80
+ // A failed `type` discriminator surfaces as a union issue on that
81
+ // key — matched on the code rather than the wording, which zod
82
+ // is free to change.
83
+ if (issue.code === 'invalid_union' && issue.path[0] === 'type') {
84
+ if (record.type === undefined) {
85
+ throw (0, validation_errors_1.validationError)(at, 'type is required. Please use read or browse.', DATA_ENTRY_HELP);
75
86
  }
76
- throw validationError(JSON.stringify(value), `${typeVal} not supported. Please use read, browse.`);
87
+ throw (0, validation_errors_1.validationError)(at, `type "${record.type}" is not supported. Please use read or browse.`, DATA_ENTRY_HELP);
77
88
  }
78
- if (issue.path?.includes('resource')) {
79
- const resVal = value.resource;
80
- if (resVal === undefined) {
81
- throw validationError(JSON.stringify(value), 'resource is required.');
89
+ if (issue.path.includes('resource')) {
90
+ if (record.resource === undefined) {
91
+ throw (0, validation_errors_1.validationError)(at, `resource is required. Please use ${(0, validation_errors_1.humanList)(VALID_LONGFORM_RESOURCES)}.`, DATA_ENTRY_HELP);
82
92
  }
83
- throw validationError(JSON.stringify(value), `${resVal} not supported. Please use ${VALID_LONGFORM_RESOURCES.join(', ')}.`);
93
+ throw (0, validation_errors_1.validationError)(at, `resource "${record.resource}" is not supported. Please use ${(0, validation_errors_1.humanList)(VALID_LONGFORM_RESOURCES)}.`, DATA_ENTRY_HELP);
94
+ }
95
+ if (issue.path.includes('slug') && !record.slug) {
96
+ throw (0, validation_errors_1.validationError)(at, 'slug is required for read data entries.', DATA_ENTRY_HELP);
97
+ }
98
+ throw (0, validation_errors_1.toValidationError)(result.error, path, value);
99
+ }
100
+ // Fields set to an explicitly empty value parse to undefined — drop the
101
+ // keys so "unset" means absent in the domain model and serialized output.
102
+ const entry = result.data;
103
+ for (const entryKey of Object.keys(entry)) {
104
+ if (entry[entryKey] === undefined) {
105
+ delete entry[entryKey];
84
106
  }
85
- throw toValidationError(result.error);
86
107
  }
87
108
  return result.data;
88
109
  }
89
- throw validationError(key, 'Incorrect Format. Please use e.g. tag.recipes');
110
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `a data entry must be a shorthand like tag.recipes, or a map with type and resource, but ${(0, validation_errors_1.describeValue)(value)} was provided.`, DATA_ENTRY_HELP);
90
111
  }
91
- function parseRouteData(data) {
112
+ function parseRouteData(data, path) {
92
113
  if (typeof data === 'string') {
93
- const result = DataShortFormSchema.safeParse(data);
94
- if (!result.success) {
95
- throw toValidationError(result.error);
96
- }
114
+ validateDataShortForm(data, path);
97
115
  return data;
98
116
  }
99
- if (typeof data !== 'object' || data === null) {
100
- throw validationError(String(data), 'Incorrect Format. Please use e.g. tag.recipes');
117
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
118
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(path), `data must be a shorthand like tag.recipes, or a map of named data entries, but ${(0, validation_errors_1.describeValue)(data)} was provided.`, DATA_ENTRY_HELP);
101
119
  }
102
120
  const record = data;
103
121
  for (const key of Object.keys(record)) {
104
122
  if (RESERVED_DATA_KEYS.includes(key)) {
105
- throw new errors_1.default.ValidationError({
106
- message: (0, tpl_1.default)(messages.badDataError),
107
- help: messages.badDataHelp
108
- });
123
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)([...path, key]), (0, tpl_1.default)(messages.badDataError, { key }), messages.badDataHelp);
109
124
  }
110
125
  if (key === 'author') {
111
- throw new errors_1.default.ValidationError({
112
- message: (0, tpl_1.default)(messages.authorDeprecatedError)
113
- });
126
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)([...path, key]), messages.authorDeprecatedError);
114
127
  }
115
128
  }
116
129
  const parsed = {};
117
130
  for (const [key, value] of Object.entries(record)) {
118
- parsed[key] = parseDataEntry(key, value);
131
+ parsed[key] = parseDataEntry(value, [...path, key]);
119
132
  }
120
133
  return parsed;
121
134
  }
122
- const TemplateField = zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).optional().default([])
135
+ const TemplateField = zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).nullish().default([])
123
136
  .transform(v => {
124
137
  if (!v || (Array.isArray(v) && v.length === 0)) {
125
138
  return [];
126
139
  }
127
140
  return Array.isArray(v) ? v : [v];
128
141
  });
129
- const RouteObjectSchema = zod_1.z.object({
142
+ // The schemas are built per route/collection so that errors raised while
143
+ // parsing nested `data` can name the exact path they came from.
144
+ const routeObjectSchema = (path) => zod_1.z.object({
130
145
  controller: zod_1.z.literal('channel').optional(),
131
146
  template: TemplateField,
132
147
  data: zod_1.z.unknown().optional(),
133
- content_type: zod_1.z.string().optional(),
134
- filter: zod_1.z.string().optional(),
135
- order: zod_1.z.string().optional(),
136
- limit: zod_1.z.union([zod_1.z.number(), zod_1.z.literal('all')]).optional(),
137
- rss: zod_1.z.boolean().optional()
148
+ content_type: OptionalStringField,
149
+ filter: OptionalStringField,
150
+ order: OptionalStringField,
151
+ limit: LimitField,
152
+ rss: OptionalBooleanField
138
153
  }).transform((val) => {
139
154
  const templates = val.template;
140
- const data = val.data !== undefined ? parseRouteData(val.data) : undefined;
155
+ const data = val.data !== undefined ? parseRouteData(val.data, [...path, 'data']) : undefined;
141
156
  if (val.controller === 'channel') {
142
157
  const route = {
143
158
  type: 'channel',
@@ -175,16 +190,16 @@ const RouteObjectSchema = zod_1.z.object({
175
190
  }
176
191
  return route;
177
192
  });
178
- const RawCollectionValueSchema = zod_1.z.object({
179
- permalink: zod_1.z.string({ message: 'Please define a permalink route.' }).optional(),
193
+ const collectionValueSchema = (path) => zod_1.z.object({
194
+ permalink: zod_1.z.string().optional(),
180
195
  template: TemplateField,
181
196
  data: zod_1.z.unknown().optional(),
182
- filter: zod_1.z.string().optional(),
183
- order: zod_1.z.string().optional(),
184
- limit: zod_1.z.union([zod_1.z.number(), zod_1.z.literal('all')]).optional(),
185
- rss: zod_1.z.boolean().optional()
197
+ filter: OptionalStringField,
198
+ order: OptionalStringField,
199
+ limit: LimitField,
200
+ rss: OptionalBooleanField
186
201
  }).transform((val) => {
187
- const data = val.data !== undefined ? parseRouteData(val.data) : undefined;
202
+ const data = val.data !== undefined ? parseRouteData(val.data, [...path, 'data']) : undefined;
188
203
  const collection = {
189
204
  permalink: val.permalink ?? '',
190
205
  templates: val.template
@@ -208,48 +223,60 @@ const RawCollectionValueSchema = zod_1.z.object({
208
223
  });
209
224
  const RouteSettingsSchema = zod_1.z.object({
210
225
  routes: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable().optional().default({}),
211
- collections: zod_1.z.record(zod_1.z.string(), RawCollectionValueSchema).nullable().optional().default({}),
226
+ collections: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable().optional().default({}),
212
227
  taxonomies: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).nullable().optional().default({})
213
228
  });
214
- function toValidationError(error) {
215
- const issue = error.issues[0];
216
- return new errors_1.default.ValidationError({
217
- message: issue.message
218
- });
229
+ /**
230
+ * Every path in routes.yaml — route paths, collection paths, permalinks and
231
+ * taxonomy permalinks — follows the same rules, so they share one message set.
232
+ *
233
+ * `allowParamNotation` is set for route and collection keys, which are mounted on
234
+ * Express verbatim: nothing rewrites `{param}` to `:param` for them the way it
235
+ * does for permalinks and taxonomies. So `/author/:slug/` is a working wildcard
236
+ * route on live sites and `/author/{slug}/` would be a dead literal path —
237
+ * rejecting :param there would break the former, and the suggested rewrite would
238
+ * silently produce the latter.
239
+ */
240
+ function validatePath(value, path, example, { allowParamNotation = false } = {}) {
241
+ const at = (0, validation_errors_1.formatLocation)(path);
242
+ if (!value.startsWith('/')) {
243
+ throw (0, validation_errors_1.validationError)(at, `"${value}" is missing a leading slash. Please use e.g. ${example}.`);
244
+ }
245
+ if (!value.endsWith('/')) {
246
+ throw (0, validation_errors_1.validationError)(at, `"${value}" is missing a trailing slash. Please use e.g. ${example}.`);
247
+ }
248
+ if (!allowParamNotation && /\/:\w+/.test(value)) {
249
+ // Suggest the same path in the notation Ghost expects, rather than a
250
+ // generic example the author then has to translate.
251
+ throw (0, validation_errors_1.validationError)(at, `"${value}" uses the :param notation. Please use "${value.replace(/\/:(\w+)/g, '/{$1}')}".`);
252
+ }
219
253
  }
220
254
  function parseRouteSettings(raw, yamlSource) {
221
255
  const obj = raw ?? {};
222
256
  const parsed = RouteSettingsSchema.safeParse(obj);
223
257
  if (!parsed.success) {
224
- throw toValidationError(parsed.error);
258
+ throw (0, validation_errors_1.toValidationError)(parsed.error, [], obj);
225
259
  }
226
260
  const { routes: rawRoutes, collections: rawCollections, taxonomies: rawTaxonomies } = parsed.data;
227
261
  const routes = [];
228
262
  if (rawRoutes) {
229
263
  for (const [path, value] of Object.entries(rawRoutes)) {
230
- if (!path.startsWith('/')) {
231
- throw validationError(path, 'A leading slash is required.');
232
- }
233
- if (!path.endsWith('/')) {
234
- throw validationError(path, 'A trailing slash is required.');
235
- }
236
- if (/\/:\w+/.test(path)) {
237
- throw validationError(path, 'Please use the following notation e.g. /{slug}/.');
238
- }
264
+ const routeLocation = ['routes', path];
265
+ validatePath(path, routeLocation, '/about/', { allowParamNotation: true });
239
266
  if (value === null || value === undefined) {
240
- throw validationError(path, 'Please define a template.', 'e.g. /about/: about');
267
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(routeLocation), 'Please define a template, e.g. /about/: about.');
241
268
  }
242
269
  if (typeof value === 'string') {
243
270
  routes.push({ type: 'template', path, templates: [value] });
244
271
  continue;
245
272
  }
246
- const routeResult = RouteObjectSchema.safeParse(value);
273
+ const routeResult = routeObjectSchema(routeLocation).safeParse(value);
247
274
  if (!routeResult.success) {
248
- throw toValidationError(routeResult.error);
275
+ throw (0, validation_errors_1.toValidationError)(routeResult.error, routeLocation, value);
249
276
  }
250
277
  const route = routeResult.data;
251
278
  if (route.type === 'template' && (!route.templates || route.templates.length === 0) && !route.data && !route.contentType) {
252
- throw validationError(path, 'Please define a template.', 'e.g. /about/: about');
279
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(routeLocation), 'Please define a template, e.g. /about/: about.');
253
280
  }
254
281
  routes.push({ ...route, path });
255
282
  }
@@ -257,48 +284,31 @@ function parseRouteSettings(raw, yamlSource) {
257
284
  const collections = [];
258
285
  if (rawCollections) {
259
286
  for (const [path, value] of Object.entries(rawCollections)) {
260
- if (!path.startsWith('/')) {
261
- throw validationError(path, 'A leading slash is required.');
262
- }
263
- if (!path.endsWith('/')) {
264
- throw validationError(path, 'A trailing slash is required.');
265
- }
266
- if (/\/:\w+/.test(path)) {
267
- throw validationError(path, 'Please use the following notation e.g. /{slug}/.');
287
+ const collectionLocation = ['collections', path];
288
+ validatePath(path, collectionLocation, '/blog/', { allowParamNotation: true });
289
+ const collectionResult = collectionValueSchema(collectionLocation).safeParse(value);
290
+ if (!collectionResult.success) {
291
+ throw (0, validation_errors_1.toValidationError)(collectionResult.error, collectionLocation, value);
268
292
  }
269
- if (!value.permalink) {
270
- throw validationError(path, 'Please define a permalink route.', 'e.g. permalink: /{slug}/');
293
+ const collection = collectionResult.data;
294
+ if (!collection.permalink) {
295
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(collectionLocation), 'Please define a permalink route, e.g. permalink: /{slug}/.');
271
296
  }
272
- if (!value.permalink.startsWith('/')) {
273
- throw validationError(value.permalink, 'A leading slash is required.');
274
- }
275
- if (!value.permalink.endsWith('/')) {
276
- throw validationError(value.permalink, 'A trailing slash is required.');
277
- }
278
- if (/\/:\w+/.test(value.permalink)) {
279
- throw validationError(value.permalink, 'Please use the following notation e.g. /{slug}/.');
280
- }
281
- collections.push({ ...value, path });
297
+ validatePath(collection.permalink, [...collectionLocation, 'permalink'], '/{slug}/');
298
+ collections.push({ ...collection, path });
282
299
  }
283
300
  }
284
301
  const taxonomies = {};
285
302
  if (rawTaxonomies) {
286
303
  for (const [key, value] of Object.entries(rawTaxonomies)) {
304
+ const taxonomyLocation = ['taxonomies', key];
287
305
  if (!['tag', 'author'].includes(key)) {
288
- throw validationError(key, 'Unknown taxonomy.');
306
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(taxonomyLocation), 'Unknown taxonomy. Please use tag or author.');
289
307
  }
290
308
  if (!value) {
291
- throw validationError(key, 'Please define a taxonomy permalink route.', 'e.g. tag: /tag/{slug}/');
292
- }
293
- if (!value.startsWith('/')) {
294
- throw validationError(value, 'A leading slash is required.');
295
- }
296
- if (!value.endsWith('/')) {
297
- throw validationError(value, 'A trailing slash is required.');
298
- }
299
- if (/\/:\w+/.test(value)) {
300
- throw validationError(value, 'Please use the following notation e.g. /{slug}/.');
309
+ throw (0, validation_errors_1.validationError)((0, validation_errors_1.formatLocation)(taxonomyLocation), `Please define a taxonomy permalink route, e.g. ${key}: /${key}/{slug}/.`);
301
310
  }
311
+ validatePath(value, taxonomyLocation, `/${key}/{slug}/`);
302
312
  if (key === 'tag') {
303
313
  taxonomies.tag = value;
304
314
  }