ghost 6.55.0 → 6.57.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 (483) hide show
  1. package/bin/validate-adapters.js +74 -0
  2. package/bin/validate-adapters.ts +87 -0
  3. package/bin/warm-compile-cache.sh +60 -0
  4. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  5. package/components/tryghost-kg-default-cards-10.3.3.tgz +0 -0
  6. package/components/tryghost-kg-default-nodes-2.1.4.tgz +0 -0
  7. package/components/tryghost-kg-default-transforms-1.3.3.tgz +0 -0
  8. package/components/tryghost-kg-html-to-lexical-1.3.3.tgz +0 -0
  9. package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
  10. package/components/tryghost-nql-string-0.0.0.tgz +0 -0
  11. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  12. package/core/app.js +1 -1
  13. package/core/boot.js +21 -25
  14. package/core/bridge.js +10 -12
  15. package/core/built/admin/assets/Combination-BDvCdg1t.js +41 -0
  16. package/core/built/admin/assets/{PolarAngleAxis-BGjf7sBu.js → PolarAngleAxis-C4qtHy1B.js} +1 -1
  17. package/core/built/admin/assets/{RadialBarChart-zeFf9mBz.js → RadialBarChart-Bh09Stsj.js} +1 -1
  18. package/core/built/admin/assets/about-C7O-AgRZ.js +1 -0
  19. package/core/built/admin/assets/{account-migration-sjHLx5dy.js → account-migration-Cv_ol1ko.js} +1 -1
  20. package/core/built/admin/assets/action-list-lGzZLHc8.js +1 -0
  21. package/core/built/admin/assets/activitypub/{account-migration-DoYXtnZ8.js → account-migration-DHFbePl6.js} +7 -7
  22. package/core/built/admin/assets/activitypub/activitypub.js +6 -6
  23. package/core/built/admin/assets/activitypub/{avatar-B3DEDB1l.js → avatar-CT4tS2_S.js} +2 -2
  24. package/core/built/admin/assets/activitypub/{avatar-flipboard-Cqrg0XMx.js → avatar-flipboard-ByYWKipo.js} +2 -2
  25. package/core/built/admin/assets/activitypub/{bluesky-sharing-Bxeh6MKW.js → bluesky-sharing-srVnSHDz.js} +16 -16
  26. package/core/built/admin/assets/activitypub/{content-formatters-BpQARh28.js → content-formatters-C2sos5Ht.js} +3 -3
  27. package/core/built/admin/assets/activitypub/{copy-D9UWIAan.js → copy-B1UBTOoZ.js} +2 -2
  28. package/core/built/admin/assets/activitypub/{dist-D8sFfdpC.js → dist-MPsb2WZ1.js} +12 -12
  29. package/core/built/admin/assets/activitypub/{domain-CWueFW6q.js → domain-DzcM9Dzo.js} +9 -9
  30. package/core/built/admin/assets/activitypub/{edit-profile-BGxPU7N5.js → edit-profile-CsQ_4xAk.js} +945 -945
  31. package/core/built/admin/assets/activitypub/{explore-DBK-u0Ch.js → explore-CJe0DZBK.js} +8 -8
  32. package/core/built/admin/assets/activitypub/{feed-Bcir5RQZ.js → feed-CKV3qWON.js} +33 -33
  33. package/core/built/admin/assets/activitypub/{field-BV-CIT3d.js → field-DckHfDJf.js} +3 -3
  34. package/core/built/admin/assets/activitypub/{hash-BC9Q0N4c.js → hash-Dlp8RM55.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{inbox-DQ4ZnC1m.js → inbox-CsPy4R0M.js} +2 -2
  36. package/core/built/admin/assets/activitypub/{inbox-yC0nfvzl.js → inbox-DAsjzUUe.js} +85 -85
  37. package/core/built/admin/assets/activitypub/{label-DTRS9TDk.js → label-DWyo9E5T.js} +3 -3
  38. package/core/built/admin/assets/activitypub/layout-DM_3pqsU.js +1 -0
  39. package/core/built/admin/assets/activitypub/{moderation-Dwl9t0pb.js → moderation-B0Inc03M.js} +11 -11
  40. package/core/built/admin/assets/activitypub/{note-B-zKsZ7r.js → note-CSE54lER.js} +7 -7
  41. package/core/built/admin/assets/activitypub/{notifications-DjJZD54t.js → notifications-RSwbKqdh.js} +9 -9
  42. package/core/built/admin/assets/activitypub/{preferences-CoU8vs6d.js → preferences-CE231n2_.js} +20 -20
  43. package/core/built/admin/assets/activitypub/{profile-BAsaJekx.js → profile-aaQ1j1Eo.js} +237 -237
  44. package/core/built/admin/assets/activitypub/{reply-CpdMeAO5.js → reply-Cjb0Vs3m.js} +2 -2
  45. package/core/built/admin/assets/activitypub/{routes-CLH3OVTP.js → routes-Djb0mc9k.js} +1139 -1150
  46. package/core/built/admin/assets/activitypub/{separator-BI1FLsYM.js → separator-D8pROI5n.js} +3 -3
  47. package/core/built/admin/assets/activitypub/{settings-DA6pNJ-Q.js → settings-DMc32IQl.js} +13 -13
  48. package/core/built/admin/assets/activitypub/{site-CQD42Pw5.js → site-DVIcsohX.js} +81 -81
  49. package/core/built/admin/assets/activitypub/{step-1-DIDg4aHb.js → step-1-9Yey9usF.js} +5 -5
  50. package/core/built/admin/assets/activitypub/{step-2-BfGe8BYt.js → step-2-DdYmKRXV.js} +6 -6
  51. package/core/built/admin/assets/activitypub/{step-3-mE9spAqw.js → step-3-hdSkcjZU.js} +10 -10
  52. package/core/built/admin/assets/activitypub/{tabs-Cg0saow1.js → tabs-CUqseYzQ.js} +317 -315
  53. package/core/built/admin/assets/activitypub/{topic-filter-DLHBZT93.js → topic-filter-Coni6OXM.js} +3 -3
  54. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-VzbN99u_.js → use-activity-pub-queries-MeHTPMQv.js} +2 -2
  55. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-CAwXTmqH.js → use-navigate-with-base-path-B046AM38.js} +115 -96
  56. package/core/built/admin/assets/activitypub/{use-reply-chain-data-Br4aOWOh.js → use-reply-chain-data-1AO-Xob6.js} +5 -5
  57. package/core/built/admin/assets/activitypub/{x-C8tAnXly.js → x-BRfRYd16.js} +2 -2
  58. package/core/built/admin/assets/add-integration-modal-m9Dv6f77.js +1 -0
  59. package/core/built/admin/assets/add-newsletter-modal-CPSVZL2H.js +1 -0
  60. package/core/built/admin/assets/add-recommendation-modal-Ci9Z5yat.js +1 -0
  61. package/core/built/admin/assets/analytics-DqSCVV8U.js +1 -0
  62. package/core/built/admin/assets/announcement-bar-modal-DU3avV7d.js +1 -0
  63. package/core/built/admin/assets/api-keys-BK0LylyK.js +1 -0
  64. package/core/built/admin/assets/api-keys-_iCT4dxr.js +1 -0
  65. package/core/built/admin/assets/{audience-DjEWNhp3.js → audience-DTJtXXWY.js} +1 -1
  66. package/core/built/admin/assets/automated-emails-PayPCT8L.js +1 -0
  67. package/core/built/admin/assets/{automations-DhKeS_U5.js → automations-162q5HjL.js} +1 -1
  68. package/core/built/admin/assets/{automations-Bx3VcFIL.js → automations-dtQ_MRZ7.js} +1 -1
  69. package/core/built/admin/assets/{bluesky-sharing-ClMd0-Ft.js → bluesky-sharing-B8Es3AuV.js} +1 -1
  70. package/core/built/admin/assets/{box-BWbhXh21.js → box-By_EgGtm.js} +1 -1
  71. package/core/built/admin/assets/brand-icon-09YqFZjV.js +1 -0
  72. package/core/built/admin/assets/{breadcrumb-BD0U2ygg.js → breadcrumb-tg5zL--z.js} +1 -1
  73. package/core/built/admin/assets/build-CsiH26uS.js +1 -0
  74. package/core/built/admin/assets/{card-DGoDJzrn.js → card-aUHX0hyR.js} +1 -1
  75. package/core/built/admin/assets/{chart-BuRT2Y6p.js → chart-BnXyfH11.js} +1 -1
  76. package/core/built/admin/assets/{chart-helpers-fjQKRVyY.js → chart-helpers-CZElTGYL.js} +1 -1
  77. package/core/built/admin/assets/checkbox-Cyo-x7mC.js +1 -0
  78. package/core/built/admin/assets/chunk.524.cd5498dd4e195f679266.js +25 -0
  79. package/core/built/admin/assets/chunk.582.6f92ec1f03734bf2ea3f.js +27 -0
  80. package/core/built/admin/assets/{chunk.481.6c7395a49484bb4583aa.js → chunk.873.b8fc05a8ab877fb819ed.js} +62 -60
  81. package/core/built/admin/assets/code-editor-view-Dq1rQ4tS.js +1 -0
  82. package/core/built/admin/assets/color-picker-field-BonBgxhU.js +1 -0
  83. package/core/built/admin/assets/color-utils-BsrwXuDz.js +1 -0
  84. package/core/built/admin/assets/combobox-uX5r_paI.js +1 -0
  85. package/core/built/admin/assets/command-DxwBO2pF.js +1 -0
  86. package/core/built/admin/assets/comments-Dn-RO-nU.js +1 -0
  87. package/core/built/admin/assets/components-CwL6a6As-B0E0-NBJ.js +1 -0
  88. package/core/built/admin/assets/confirmation-modal-B6D6mk6R.js +1 -0
  89. package/core/built/admin/assets/{container-BYz2Ed39.js → container-LiZf3XdY.js} +1 -1
  90. package/core/built/admin/assets/content-api-modal-BxQ-7T6u.js +1 -0
  91. package/core/built/admin/assets/copy-field-BAxL4Zqn.js +1 -0
  92. package/core/built/admin/assets/currency-Dy4Tc2R2.js +1 -0
  93. package/core/built/admin/assets/custom-integration-modal---d_l7lc.js +1 -0
  94. package/core/built/admin/assets/{data-list-16rkJYYi.js → data-list-CupF7bjM.js} +1 -1
  95. package/core/built/admin/assets/{date-range-select-BFp58EMk.js → date-range-select-PB2n1HZf.js} +1 -1
  96. package/core/built/admin/assets/debounce-Dg2fW5Rg.js +3 -0
  97. package/core/built/admin/assets/design-and-theme-modal-DYRT207a.js +23 -0
  98. package/core/built/admin/assets/dirty-confirm-dialog-BnDJ39ao.js +1 -0
  99. package/core/built/admin/assets/disabled-sources-indicator-iMHrkyV3.js +1 -0
  100. package/core/built/admin/assets/dist-B2PvRwLn.js +1 -0
  101. package/core/built/admin/assets/{dist-DGzPJ_bO.js → dist-Cb5RSHSg.js} +1 -1
  102. package/core/built/admin/assets/{dist-P_ohUlTi.js → dist-CqO2lWS02.js} +1 -1
  103. package/core/built/admin/assets/{dist-pHiOxyxa.js → dist-D5vhMdXf.js} +1 -1
  104. package/core/built/admin/assets/dist-DlCyLrOC.js +1 -0
  105. package/core/built/admin/assets/dist-WeOIvSYM.js +23 -0
  106. package/core/built/admin/assets/{dist-DyViJwIy.js → dist-cFzKLG7y.js} +3 -3
  107. package/core/built/admin/assets/dist-j1xxxnY8.js +1 -0
  108. package/core/built/admin/assets/dist-myQaY0ka.js +1 -0
  109. package/core/built/admin/assets/domain-BR8FIdjD.js +1 -0
  110. package/core/built/admin/assets/{dropzone-DlK-K2DQ.js → dropzone-hNxmUvwD.js} +1 -1
  111. package/core/built/admin/assets/{edit-profile-BKT-REJw.js → edit-profile-CENrkY0l.js} +1 -1
  112. package/core/built/admin/assets/editor-B18D0lm8.js +8 -0
  113. package/core/built/admin/assets/embed-signup-form-modal-BsCYUMvQ.js +9 -0
  114. package/core/built/admin/assets/{empty-indicator-oX1u1Pkn.js → empty-indicator-WB1WgT9h.js} +1 -1
  115. package/core/built/admin/assets/{explore-ClUpJZOp.js → explore-BmrnljWw.js} +1 -1
  116. package/core/built/admin/assets/{feed-DF92dUMP.js → feed-Dy4li6i8.js} +1 -1
  117. package/core/built/admin/assets/{field-Do7lieBA.js → field-Dh_lwk13.js} +1 -1
  118. package/core/built/admin/assets/filter-sources-D2zDuJH5.js +1 -0
  119. package/core/built/admin/assets/filters-3JBQcNtJ.js +1 -0
  120. package/core/built/admin/assets/filters-CFt_BDe4.js +1 -0
  121. package/core/built/admin/assets/first-promoter-modal-D6Rjxugw.js +1 -0
  122. package/core/built/admin/assets/format-url-C-t8G6Qd.js +1 -0
  123. package/core/built/admin/assets/{ghost-a9c788f6f0b1ea6cf0f14ca4b13f4496.css → ghost-d38c30b866e59f2e06a357b5eb844fe5.css} +1 -1
  124. package/core/built/admin/assets/{ghost-c4057474943effc568c5659ccc4909d7.js → ghost-d683fbeb945b13155ea669caa5d8db41.js} +420 -398
  125. package/core/built/admin/assets/{ghost-dark-db36d795d21c61426837df40af270966.css → ghost-dark-1bffd5099ba7a749303133efacf8480b.css} +1 -1
  126. package/core/built/admin/assets/{gift-link-modal-f9VIMNDv.js → gift-link-modal-zMtlJhLQ.js} +1 -1
  127. package/core/built/admin/assets/{gift-links-CsUhefWG.js → gift-links-CVuqLhsZ.js} +1 -1
  128. package/core/built/admin/assets/global-data-provider-B949LDXJ.js +1 -0
  129. package/core/built/admin/assets/grid-CUciBfjf.js +1 -0
  130. package/core/built/admin/assets/{growth-CVw1My4S.js → growth-C38Xtp8D.js} +2 -2
  131. package/core/built/admin/assets/{growth-B3I6gNLm.js → growth-CFws67_i.js} +1 -1
  132. package/core/built/admin/assets/history-modal-ILAOkbxH.js +1 -0
  133. package/core/built/admin/assets/{hooks-CixO01lL.js → hooks-D6EE7BIt.js} +2 -2
  134. package/core/built/admin/assets/html-field-9a9Id_2q.js +1 -0
  135. package/core/built/admin/assets/iframe-buffering-e8vH4-Qn.js +1 -0
  136. package/core/built/admin/assets/images-CrQKVc9Q.js +1 -0
  137. package/core/built/admin/assets/{inbox-CFBSu4Ed.js → inbox-BrSRzyvz.js} +6 -6
  138. package/core/built/admin/assets/index-BHy2DZX-.js +67 -0
  139. package/core/built/admin/assets/index-Ds2iUoF6.css +1 -0
  140. package/core/built/admin/assets/index.es-B9tvf-t4.js +1 -0
  141. package/core/built/admin/assets/{inline-EMAm3okk.js → inline-Cw-gigDW.js} +1 -1
  142. package/core/built/admin/assets/input-group-6vEPvX9S.js +1 -0
  143. package/core/built/admin/assets/{input-surface-BpAjZXY5.js → input-surface-BdOe4KzO.js} +1 -1
  144. package/core/built/admin/assets/integration-header-B4DyXV06.js +1 -0
  145. package/core/built/admin/assets/integrations-BT6_iJvu.js +1 -0
  146. package/core/built/admin/assets/invite-user-modal-5xDCEw90.js +1 -0
  147. package/core/built/admin/assets/isEmail-BOfC647y.js +1 -0
  148. package/core/built/admin/assets/koenig-editor-base-BWLEB9Vf.js +1 -0
  149. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +9535 -9527
  150. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +124 -124
  151. package/core/built/admin/assets/{koenig-lexical-f8vHRYvz.js → koenig-lexical-Cj62r_y9.js} +86 -86
  152. package/core/built/admin/assets/{kpi-card-DSap9rAy.js → kpi-card-DOUnkZcN.js} +1 -1
  153. package/core/built/admin/assets/{kpi-card-DU0rn9Cj.js → kpi-card-IHDo8Q56.js} +1 -1
  154. package/core/built/admin/assets/{kpi-helpers-Dz33AV6h.js → kpi-helpers-CjUdECAK.js} +1 -1
  155. package/core/built/admin/assets/{kpi-tabs-BtTTrKvJ.js → kpi-tabs-X3DkOYbI.js} +1 -1
  156. package/core/built/admin/assets/{label-DS8Mi6G5.js → label-Dq6QaOuS.js} +1 -1
  157. package/core/built/admin/assets/label-picker-8YlhS2U3.js +1 -0
  158. package/core/built/admin/assets/labels-DAPjKPy2.js +1 -0
  159. package/core/built/admin/assets/layout-TMj4P-vv.js +1 -0
  160. package/core/built/admin/assets/limit-modal-BRPsit_B.js +1 -0
  161. package/core/built/admin/assets/link-helpers-Bzkk68GD.js +1 -0
  162. package/core/built/admin/assets/{list-page-B6ANtzkd.js → list-page-CdsnQR9N.js} +1 -1
  163. package/core/built/admin/assets/member-custom-fields-CmvsuuV_.js +1 -0
  164. package/core/built/admin/assets/member-detail-DCvRrkmJ.js +1 -0
  165. package/core/built/admin/assets/members-DxbSKngD.js +11 -0
  166. package/core/built/admin/assets/modal-page-BMTzFHVO.js +1 -0
  167. package/core/built/admin/assets/{moderation-DySbgyUS.js → moderation-Da5lhhWh.js} +1 -1
  168. package/core/built/admin/assets/multi-select-combobox-CYdkH7KQ.js +1 -0
  169. package/core/built/admin/assets/navigation-modal-BIoTwtMy.js +1 -0
  170. package/core/built/admin/assets/newsletter-BptlVoJm.js +1 -0
  171. package/core/built/admin/assets/newsletter-detail-modal-BIvxqE0N.js +1 -0
  172. package/core/built/admin/assets/newsletter-emails-Bf8IZLsP.js +1 -0
  173. package/core/built/admin/assets/newsletters-BgrIZk0V.js +1 -0
  174. package/core/built/admin/assets/{newsletters-BXJbJgA-.js → newsletters-Du0lzskS.js} +1 -1
  175. package/core/built/admin/assets/{note-C8kxrz6w.js → note-DYcLOmDb.js} +1 -1
  176. package/core/built/admin/assets/{notifications-CgtSfX7t.js → notifications-B2SPFIV9.js} +1 -1
  177. package/core/built/admin/assets/{offers-DEniVRD5.js → offers-Um6ab71O.js} +1 -1
  178. package/core/built/admin/assets/offers-container-modal-BZnZITMw.js +1 -0
  179. package/core/built/admin/assets/{onboarding-route-4qtziA9d.js → onboarding-route-DgdfxkQh.js} +1 -1
  180. package/core/built/admin/assets/overview-BYQJXSog.js +1 -0
  181. package/core/built/admin/assets/overview-Dt2_mR6U.js +1 -0
  182. package/core/built/admin/assets/{page-header-B3Wb9Jqv.js → page-header-CpmxJj5B.js} +1 -1
  183. package/core/built/admin/assets/{pages-B4goRPUn.js → pages-BVMnpI2O.js} +1 -1
  184. package/core/built/admin/assets/pintura-modal-B4MuBuuO.js +1 -0
  185. package/core/built/admin/assets/portal-frame-BF0NBIji.js +1 -0
  186. package/core/built/admin/assets/portal-modal-DMVbm0oy.js +1 -0
  187. package/core/built/admin/assets/{post-analytics-We-ko5Cb.js → post-analytics-CXWBOGyP.js} +1 -1
  188. package/core/built/admin/assets/post-analytics-header-ChzjXVPt.js +1 -0
  189. package/core/built/admin/assets/{post-analytics-provider-B6UynTGb.js → post-analytics-provider-Cgw4U_fw.js} +1 -1
  190. package/core/built/admin/assets/{post-share-modal-DFfO93_0.js → post-share-modal-B9Vmk_XM.js} +1 -1
  191. package/core/built/admin/assets/{posts-DhXE7b6r.js → posts-CxG7v0-M.js} +1 -1
  192. package/core/built/admin/assets/preferences-BfzJmnsd.js +5 -0
  193. package/core/built/admin/assets/preview-chrome-BOVO6_PE.js +1 -0
  194. package/core/built/admin/assets/preview-modal-Dw_HtD6S.js +1 -0
  195. package/core/built/admin/assets/profile-BT5vtv9b.js +1 -0
  196. package/core/built/admin/assets/radio-group-I7ou7PoJ.js +1 -0
  197. package/core/built/admin/assets/{referrers-pmJT4k3-.js → referrers-B9QDAfYm.js} +1 -1
  198. package/core/built/admin/assets/{router-provider-C1R4AZ2o.js → router-provider-DSQfprxH.js} +1 -1
  199. package/core/built/admin/assets/select-D9oU1IoM.js +1 -0
  200. package/core/built/admin/assets/settings-CfZFbyu_.js +4 -0
  201. package/core/built/admin/assets/{settings-WXNeWyU1.js → settings-CpvHWix7.js} +1 -1
  202. package/core/built/admin/assets/settings-breadcrumbs-K0USP2nw.js +1 -0
  203. package/core/built/admin/assets/{shade-app-B3heOAfz-CGXQwWeO.js → shade-app-B3heOAfz-BhQXxNkT.js} +1 -1
  204. package/core/built/admin/assets/{share-modal-DsgW3wbg.js → share-modal-ClIyPzc5.js} +1 -1
  205. package/core/built/admin/assets/slack-modal-1XXqOfiw.js +1 -0
  206. package/core/built/admin/assets/social-urls-CHQ9cTAK.js +1 -0
  207. package/core/built/admin/assets/{sort-button-Bb_FCl7e.js → sort-button-CdBsm40v.js} +1 -1
  208. package/core/built/admin/assets/{source-icon-BeaRxUn9.js → source-icon-CEYmVLXR.js} +1 -1
  209. package/core/built/admin/assets/{stack-xiN0eQ6Z.js → stack-CIfOAAVf.js} +1 -1
  210. package/core/built/admin/assets/{stats-Bjj_kmJ1.js → stats-D8nZCTy5.js} +1 -1
  211. package/core/built/admin/assets/{stats-view-BxPbW6K1.js → stats-view-CugFVf0g.js} +1 -1
  212. package/core/built/admin/assets/{step-1-B1e3-1F8.js → step-1-DOYjrORn.js} +1 -1
  213. package/core/built/admin/assets/{step-2-C5WaeBJo.js → step-2-vA6RsarH.js} +1 -1
  214. package/core/built/admin/assets/{step-3-B46iVPwu.js → step-3-BtIBxMId.js} +2 -2
  215. package/core/built/admin/assets/stripe-button-UFP4QRXd.js +1 -0
  216. package/core/built/admin/assets/stripe-connect-modal-C_L3uM6n.js +1 -0
  217. package/core/built/admin/assets/switch-CE2NuMn-.js +1 -0
  218. package/core/built/admin/assets/{table-CB-4_HBJ.js → table-TMCgCQK7.js} +1 -1
  219. package/core/built/admin/assets/tabs-Dd6oOKbv.js +1 -0
  220. package/core/built/admin/assets/tag-detail-D3l-UJPR.js +1 -0
  221. package/core/built/admin/assets/tags-BwCgmr5v.js +1 -0
  222. package/core/built/admin/assets/tags-WdKQGWR8.js +1 -0
  223. package/core/built/admin/assets/testimonials-modal-CqWp-xXJ.js +1 -0
  224. package/core/built/admin/assets/{text-DwtjwGkh.js → text-DU9Hv33_.js} +1 -1
  225. package/core/built/admin/assets/textarea-d9qEkMOP.js +1 -0
  226. package/core/built/admin/assets/tier-detail-modal-BkcR2u0A.js +1 -0
  227. package/core/built/admin/assets/{tiers-DYsa4DCo.js → tiers-Da6kxHQP.js} +1 -1
  228. package/core/built/admin/assets/toggle-group-Guorw93z.js +1 -0
  229. package/core/built/admin/assets/{topic-filter-DAFT87tQ.js → topic-filter-CbgoWIHn.js} +1 -1
  230. package/core/built/admin/assets/transistor-modal-DuNnnpal.js +1 -0
  231. package/core/built/admin/assets/unsplash-modal-y2bVwTHH.js +1 -0
  232. package/core/built/admin/assets/{use-analytics-data-S0FTd43s.js → use-analytics-data-B-b4wNSC.js} +1 -1
  233. package/core/built/admin/assets/use-check-theme-limit-error-m09J38Mq.js +2 -0
  234. package/core/built/admin/assets/use-feature-flag-ud0Qz8vt.js +1 -0
  235. package/core/built/admin/assets/{use-filter-params-Gpoq2E1L.js → use-filter-params-BnbBDc7T.js} +1 -1
  236. package/core/built/admin/assets/use-filterable-api-iMpDZBxD.js +1 -0
  237. package/core/built/admin/assets/use-form-vRjI0Kwk.js +1 -0
  238. package/core/built/admin/assets/{use-growth-stats-CIaiHOVb.js → use-growth-stats-DPU5rt3W.js} +1 -1
  239. package/core/built/admin/assets/use-hash-link-navigation-guard-B9j6HIrV.js +1 -0
  240. package/core/built/admin/assets/use-limiter-BkN3E4gw.js +2 -0
  241. package/core/built/admin/assets/use-pintura-config-C_z8HTG2.js +1 -0
  242. package/core/built/admin/assets/use-pintura-editor-DNgbkhGp.js +1 -0
  243. package/core/built/admin/assets/{use-post-referrers-Cq2vBPrA.js → use-post-referrers-C2mXyrp-.js} +1 -1
  244. package/core/built/admin/assets/use-query-params-DHhhu8wi.js +1 -0
  245. package/core/built/admin/assets/{use-reply-chain-data-DBDRtGu-.js → use-reply-chain-data-DaK8q2qQ.js} +1 -1
  246. package/core/built/admin/assets/use-setting-group-YlYcoNyP.js +1 -0
  247. package/core/built/admin/assets/use-settings-navigation-Bf1g1rEh.js +1 -0
  248. package/core/built/admin/assets/{use-simple-pagination-CjYNxdwe.js → use-simple-pagination-D9ckKo5-.js} +1 -1
  249. package/core/built/admin/assets/{use-tinybird-query-falHAtuK.js → use-tinybird-query-GSa32hVw.js} +1 -1
  250. package/core/built/admin/assets/{use-tinybird-token-D7-8ND1y.js → use-tinybird-token-CKLOZFsw.js} +1 -1
  251. package/core/built/admin/assets/use-url-input-z-p0Kewm.js +5 -0
  252. package/core/built/admin/assets/user-detail-modal-BMxOA4Sv.js +1 -0
  253. package/core/built/admin/assets/{users-Dkv8NQZe.js → users-B6hIds6n.js} +1 -1
  254. package/core/built/admin/assets/validator-Cr0sMKuW.js +7 -0
  255. package/core/built/admin/assets/{virtual-list-CvnC9zF2.js → virtual-list-RHeEL05L.js} +1 -1
  256. package/core/built/admin/assets/{web-jFYWCKDn.js → web-Bw2QMO5u.js} +2 -2
  257. package/core/built/admin/assets/web-xJtcwMy4.js +1 -0
  258. package/core/built/admin/assets/zapier-modal-BP2f4-vY.js +1 -0
  259. package/core/built/admin/index.html +20 -18
  260. package/core/frontend/helpers/authors.js +1 -1
  261. package/core/frontend/helpers/link.js +3 -8
  262. package/core/frontend/helpers/tags.js +1 -1
  263. package/core/frontend/meta/author-url.js +2 -2
  264. package/core/frontend/meta/url.js +4 -4
  265. package/core/frontend/services/data/fetch-data.js +10 -5
  266. package/core/frontend/services/proxy.js +1 -1
  267. package/core/frontend/services/routing/api-adapter.js +115 -0
  268. package/core/frontend/services/routing/api-adapter.ts +157 -0
  269. package/core/frontend/services/routing/collection-router.js +5 -3
  270. package/core/frontend/services/routing/controllers/index.js +1 -1
  271. package/core/frontend/services/routing/controllers/rss.js +26 -31
  272. package/core/frontend/services/routing/controllers/rss.ts +66 -0
  273. package/core/frontend/services/routing/controllers/static.js +8 -7
  274. package/core/frontend/services/routing/events.js +20 -6
  275. package/core/frontend/services/routing/parent-router.js +17 -4
  276. package/core/frontend/services/routing/permalink-adapter.js +13 -0
  277. package/core/frontend/services/routing/permalink-adapter.ts +10 -0
  278. package/core/frontend/services/routing/registry.js +59 -33
  279. package/core/frontend/services/routing/router-manager.js +24 -22
  280. package/core/frontend/services/routing/static-routes-router.js +4 -4
  281. package/core/frontend/services/routing/taxonomy-router.js +6 -2
  282. package/core/frontend/services/sitemap/base-site-map-generator.js +1 -28
  283. package/core/frontend/services/sitemap/site-map-manager.js +22 -57
  284. package/core/server/adapters/route-settings/utils.js +10 -2
  285. package/core/server/adapters/route-settings/utils.ts +12 -2
  286. package/core/server/api/endpoints/email-post.js +1 -1
  287. package/core/server/api/endpoints/previews.js +1 -1
  288. package/core/server/api/endpoints/search-index-public.js +3 -3
  289. package/core/server/api/endpoints/search-index.js +4 -4
  290. package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -2
  291. package/core/server/api/endpoints/utils/serializers/input/comments.js +1 -1
  292. package/core/server/api/endpoints/utils/serializers/input/pages.js +3 -3
  293. package/core/server/api/endpoints/utils/serializers/input/posts.js +3 -3
  294. package/core/server/api/endpoints/utils/serializers/input/tags.js +1 -1
  295. package/core/server/api/endpoints/utils/serializers/input/users.js +2 -2
  296. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +31 -13
  297. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +2 -2
  298. package/core/server/api/endpoints/utils/serializers/output/mappers/tags.js +2 -2
  299. package/core/server/api/endpoints/utils/serializers/output/mappers/users.js +8 -0
  300. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +18 -11
  301. package/core/server/data/migrations/versions/6.56/2026-08-03-19-27-51-add-automation-run-step-id-to-automated-email-recipients.js +8 -0
  302. package/core/server/data/migrations/versions/6.56/2026-08-04-14-42-39-restrict-notification-add-permission-to-administrators.js +12 -0
  303. package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +74 -0
  304. package/core/server/data/migrations/versions/6.57/2026-08-04-18-54-14-reset-automation-email-analytics.js +25 -0
  305. package/core/server/data/schema/commands.js +21 -5
  306. package/core/server/data/schema/fixtures/fixtures.json +2 -2
  307. package/core/server/data/schema/schema.js +25 -5
  308. package/core/server/lib/common/to-plain.ts +1 -1
  309. package/core/server/models/post.js +12 -3
  310. package/core/server/services/adapter-manager/adapter-manager.js +1 -45
  311. package/core/server/services/adapter-manager/adapter-manager.ts +2 -48
  312. package/core/server/services/adapter-manager/adapter-paths.js +24 -0
  313. package/core/server/services/adapter-manager/adapter-paths.ts +21 -0
  314. package/core/server/services/adapter-manager/base-classes.js +22 -0
  315. package/core/server/services/adapter-manager/base-classes.ts +22 -0
  316. package/core/server/services/adapter-manager/index.js +4 -27
  317. package/core/server/services/adapter-manager/index.ts +4 -31
  318. package/core/server/services/adapter-manager/utils.js +50 -0
  319. package/core/server/services/adapter-manager/utils.ts +57 -0
  320. package/core/server/services/audience-feedback/audience-feedback-controller.js +1 -1
  321. package/core/server/services/audience-feedback/audience-feedback-service.js +2 -2
  322. package/core/server/services/automations/automations-repository.ts +3 -1
  323. package/core/server/services/automations/database-automations-repository.js +33 -14
  324. package/core/server/services/automations/database-automations-repository.ts +41 -15
  325. package/core/server/services/automations/get-scheduler-idempotency-key.js +13 -0
  326. package/core/server/services/automations/get-scheduler-idempotency-key.ts +8 -0
  327. package/core/server/services/automations/poll.js +3 -1
  328. package/core/server/services/automations/poll.ts +4 -1
  329. package/core/server/services/automations/service.js +7 -3
  330. package/core/server/services/automations/service.ts +7 -3
  331. package/core/server/services/comments/comments-service-emails.js +1 -1
  332. package/core/server/services/comments/comments-service.js +1 -1
  333. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +11 -2
  334. package/core/server/services/email-analytics/email-analytics-service.js +1 -1
  335. package/core/server/services/email-service/email-service-wrapper.js +2 -1
  336. package/core/server/services/email-service/mailgun-email-provider.js +15 -0
  337. package/core/server/services/gift-links/CONTEXT.md +9 -0
  338. package/core/server/services/gifts/CONTEXT.md +55 -0
  339. package/core/server/services/gifts/README.md +28 -0
  340. package/core/server/services/gifts/gift-bookshelf-repository.js +65 -45
  341. package/core/server/services/gifts/gift-bookshelf-repository.ts +203 -74
  342. package/core/server/services/gifts/gift-checkout-adapter.js +59 -0
  343. package/core/server/services/gifts/gift-checkout-offer.js +74 -0
  344. package/core/server/services/gifts/gift-checkout-offer.ts +127 -0
  345. package/core/server/services/gifts/gift-codec.js +63 -0
  346. package/core/server/services/gifts/gift-codec.ts +62 -0
  347. package/core/server/services/gifts/gift-controller.js +6 -31
  348. package/core/server/services/gifts/gift-controller.ts +6 -69
  349. package/core/server/services/gifts/gift-email-service.ts +3 -2
  350. package/core/server/services/gifts/gift-schema.js +34 -0
  351. package/core/server/services/gifts/gift-schema.ts +39 -0
  352. package/core/server/services/gifts/gift-service-wrapper.js +13 -11
  353. package/core/server/services/gifts/gift-service.js +265 -52
  354. package/core/server/services/gifts/gift-service.ts +431 -97
  355. package/core/server/services/gifts/gift.ts +16 -39
  356. package/core/server/services/indexnow-ping/indexnow-ping-service.js +1 -1
  357. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +2 -4
  358. package/core/server/services/lib/mailgun-client.js +3 -3
  359. package/core/server/services/link-tracking/link-click-repository.js +6 -1
  360. package/core/server/services/link-tracking/link-click-tracking-service.js +12 -3
  361. package/core/server/services/media-inliner/external-media-inliner.js +12 -8
  362. package/core/server/services/member-attribution/url-translator.js +5 -7
  363. package/core/server/services/member-welcome-emails/member-welcome-email-renderer.js +4 -3
  364. package/core/server/services/member-welcome-emails/service.js +79 -15
  365. package/core/server/services/members/api.js +2 -3
  366. package/core/server/services/members/import-export/import/completion-email.js +8 -4
  367. package/core/server/services/members/import-export/import/completion-email.ts +9 -4
  368. package/core/server/services/members/import-export/import/importer.js +25 -4
  369. package/core/server/services/members/import-export/import/importer.ts +27 -6
  370. package/core/server/services/members/import-export/import/row.ts +5 -1
  371. package/core/server/services/members/import-export/index.js +6 -2
  372. package/core/server/services/members/import-export/index.ts +10 -4
  373. package/core/server/services/members/members-api/controllers/router-controller.js +38 -36
  374. package/core/server/services/members/members-api/members-api.js +13 -7
  375. package/core/server/services/members/members-api/repositories/event-repository.js +4 -94
  376. package/core/server/services/members/members-api/services/member-bread-service.js +3 -3
  377. package/core/server/services/members/members-api/services/payments-service.js +6 -68
  378. package/core/server/services/members-custom-fields/queries.js +4 -13
  379. package/core/server/services/members-custom-fields/queries.ts +4 -13
  380. package/core/server/services/members-custom-fields/schema.js +19 -21
  381. package/core/server/services/members-custom-fields/schema.ts +18 -20
  382. package/core/server/services/members-custom-fields/storage.js +94 -27
  383. package/core/server/services/members-custom-fields/storage.ts +114 -39
  384. package/core/server/services/members-custom-fields/values-service.js +98 -103
  385. package/core/server/services/members-custom-fields/values-service.ts +116 -114
  386. package/core/server/services/mentions/resource-service.js +1 -1
  387. package/core/server/services/mentions/service.js +2 -2
  388. package/core/server/services/oembed/oembed-service.js +44 -3
  389. package/core/server/services/posts/posts-service.js +11 -0
  390. package/core/server/services/route-settings/dynamic-routing-service.js +10 -62
  391. package/core/server/services/route-settings/route-settings-parser.js +25 -25
  392. package/core/server/services/route-settings/route-settings-parser.ts +27 -27
  393. package/core/server/services/route-settings/validation-errors.js +68 -4
  394. package/core/server/services/route-settings/validation-errors.ts +79 -4
  395. package/core/server/services/slack-ping/slack-ping-service.js +2 -2
  396. package/core/server/services/slack-ping/slack-ping-service.ts +3 -5
  397. package/core/server/services/stats/content-stats-service.js +3 -3
  398. package/core/server/services/stats/posts-stats-service.js +29 -25
  399. package/core/server/services/stripe/services/webhook/charge-refunded-event-service.js +1 -1
  400. package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +16 -4
  401. package/core/server/services/stripe/stripe-api.js +10 -0
  402. package/core/server/services/url/config.js +90 -135
  403. package/core/server/services/url/index.js +6 -49
  404. package/core/server/services/url/lazy-find-resource.js +14 -11
  405. package/core/server/services/url/lazy-find-resource.ts +14 -11
  406. package/core/server/services/url/lazy-url-service.js +174 -94
  407. package/core/server/services/url/lazy-url-service.ts +233 -97
  408. package/core/server/services/url/routable-resources.js +62 -71
  409. package/core/server/services/url/router-filter.js +12 -4
  410. package/core/server/services/url/router-filter.ts +12 -4
  411. package/core/server/services/webhooks/index.js +1 -1
  412. package/core/server/services/webhooks/serialize.js +2 -1
  413. package/core/server/web/gift-preview/controller.js +10 -25
  414. package/core/shared/config/env/config.testing-mysql.json +1 -2
  415. package/core/shared/config/env/config.testing.json +1 -2
  416. package/core/shared/events/index.js +1 -2
  417. package/core/shared/labs.js +4 -4
  418. package/package.json +10 -10
  419. package/pnpm-lock.yaml +27 -20
  420. package/pnpm-workspace.yaml +3 -2
  421. package/tsconfig.json +1 -0
  422. package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
  423. package/core/built/admin/assets/Combination-CJG7Flp-.js +0 -41
  424. package/core/built/admin/assets/activitypub/layout-qx-bUL1k.js +0 -1
  425. package/core/built/admin/assets/automated-emails-DRy7qY-J.js +0 -7
  426. package/core/built/admin/assets/checkbox-CWa28lgO.js +0 -1
  427. package/core/built/admin/assets/chunk.524.cffd399783a519e404a9.js +0 -25
  428. package/core/built/admin/assets/chunk.582.eebf0d0b2d202bb746a5.js +0 -27
  429. package/core/built/admin/assets/code-editor-view-CCr0rBWS.js +0 -1
  430. package/core/built/admin/assets/comments-DyUSMUdj.js +0 -1
  431. package/core/built/admin/assets/disabled-sources-indicator-CUxMfiPa.js +0 -1
  432. package/core/built/admin/assets/dist-2Tnz2Yfq.js +0 -1
  433. package/core/built/admin/assets/dist-CjY-f5Z1.js +0 -1
  434. package/core/built/admin/assets/dist-DDY6GRVz.js +0 -1
  435. package/core/built/admin/assets/dist-DG78yroX.js +0 -23
  436. package/core/built/admin/assets/domain-C0bV2UV8.js +0 -1
  437. package/core/built/admin/assets/editor-Dp865O-4.js +0 -8
  438. package/core/built/admin/assets/esm-CFX93H5M.js +0 -2
  439. package/core/built/admin/assets/filter-sources-BV2rnpfA.js +0 -1
  440. package/core/built/admin/assets/filters-CUXJ2Nm9.js +0 -1
  441. package/core/built/admin/assets/filters-DfbIWc_l.js +0 -1
  442. package/core/built/admin/assets/index-9Cw8z3rA.css +0 -1
  443. package/core/built/admin/assets/index-BGG7NckO.js +0 -67
  444. package/core/built/admin/assets/input-group-BSgG_lVw.js +0 -1
  445. package/core/built/admin/assets/label-picker-1DvSuLA1.js +0 -1
  446. package/core/built/admin/assets/labels-CDSUt4J_.js +0 -1
  447. package/core/built/admin/assets/layout-yQEi2qDM.js +0 -1
  448. package/core/built/admin/assets/link-helpers-7EYqvvHs.js +0 -1
  449. package/core/built/admin/assets/member-custom-fields-yOMHyAg9.js +0 -1
  450. package/core/built/admin/assets/member-detail-BAq7gDaa.js +0 -1
  451. package/core/built/admin/assets/members-CQpVFJu4.js +0 -10
  452. package/core/built/admin/assets/modals-ReORvWnu.js +0 -31
  453. package/core/built/admin/assets/newsletter-CJQvtHqN.js +0 -1
  454. package/core/built/admin/assets/newsletters-B3QQXfGT.js +0 -1
  455. package/core/built/admin/assets/nql-BsgFMd93.js +0 -1
  456. package/core/built/admin/assets/overview-Bf2sbznq.js +0 -1
  457. package/core/built/admin/assets/overview-CBfePxcr.js +0 -1
  458. package/core/built/admin/assets/post-analytics-header-Bmc9su6q.js +0 -1
  459. package/core/built/admin/assets/preferences-DJPfHEGu.js +0 -5
  460. package/core/built/admin/assets/profile-DqBQp-gT.js +0 -1
  461. package/core/built/admin/assets/select-C5_xEt5b.js +0 -1
  462. package/core/built/admin/assets/settings-BwiVIXau.js +0 -4
  463. package/core/built/admin/assets/social-urls-BQPFEk1_.js +0 -8
  464. package/core/built/admin/assets/switch-z5Y6Uzt6.js +0 -1
  465. package/core/built/admin/assets/tabs-CCEgKYzq.js +0 -1
  466. package/core/built/admin/assets/tags-Cg2VJGmG.js +0 -1
  467. package/core/built/admin/assets/textarea-Bjccvh_E.js +0 -1
  468. package/core/built/admin/assets/toggle-group-b3IlxvhV.js +0 -1
  469. package/core/built/admin/assets/web-B_5GZRvH.js +0 -1
  470. package/core/server/services/gifts/gift-repository.js +0 -2
  471. package/core/server/services/gifts/gift-repository.ts +0 -29
  472. package/core/server/services/route-settings/activation-bridge.js +0 -174
  473. package/core/server/services/route-settings/activation-bridge.ts +0 -250
  474. package/core/server/services/url/local-file-cache.js +0 -75
  475. package/core/server/services/url/queue.js +0 -260
  476. package/core/server/services/url/resource.js +0 -102
  477. package/core/server/services/url/resources.js +0 -480
  478. package/core/server/services/url/url-generator.js +0 -276
  479. package/core/server/services/url/url-service-facade.js +0 -366
  480. package/core/server/services/url/url-service-facade.ts +0 -519
  481. package/core/server/services/url/url-service.js +0 -387
  482. package/core/server/services/url/urls.js +0 -140
  483. package/core/shared/events/url-resource-updated-event.js +0 -33
@@ -1,52 +1,47 @@
1
- const _ = require('lodash');
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.rssController = rssController;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const node_url_1 = __importDefault(require("node:url"));
2
9
  const debug = require('@tryghost/debug')('services:routing:controllers:rss');
3
- const url = require('url');
4
10
  const security = require('@tryghost/security');
5
11
  const settingsCache = require('../../../../shared/settings-cache');
6
12
  const rssService = require('../../rss');
7
13
  const renderer = require('../../rendering');
8
14
  const dataService = require('../../data');
9
-
10
- // @TODO: is this really correct? Should we be using meta data title?
15
+ /**
16
+ * Generates the title for the RSS feed based on author, tag, or publication settings.
17
+ */
11
18
  function getTitle(relatedData) {
12
- relatedData = relatedData || {};
13
- let titleStart = _.get(relatedData, 'author[0].name') || _.get(relatedData, 'tag[0].name') || '';
14
-
19
+ const data = relatedData || {};
20
+ let titleStart = lodash_1.default.get(data, 'author[0].name') || lodash_1.default.get(data, 'tag[0].name') || '';
15
21
  titleStart += titleStart ? ' - ' : '';
16
22
  return titleStart + settingsCache.get('title');
17
23
  }
18
-
19
24
  /**
20
- * @description RSS controller.
21
- *
22
- * @TODO: The collection controller does almost the same. Merge!
23
- * @param {Object} req
24
- * @param {Object} res
25
- * @param {Function} next
25
+ * RSS routing controller.
26
+ * Fetches posts/meta data and delegates rendering to `rssService`.
26
27
  */
27
- module.exports = function rssController(req, res, next) {
28
+ function rssController(req, res, next) {
28
29
  debug('rssController');
29
-
30
30
  const pathOptions = {
31
31
  page: 1, // required for fetchData
32
32
  slug: req.params.slug ? security.string.safe(req.params.slug) : undefined
33
33
  };
34
-
35
34
  // CASE: Ghost is using an rss cache - normalize the URL for use as a key
36
- // @TODO: This belongs to the rss service O_o
37
- const baseUrl = url.parse(req.originalUrl).pathname;
38
-
39
- dataService.fetchData(pathOptions, res.routerOptions, res.locals)
35
+ const baseUrl = node_url_1.default.parse(req.originalUrl).pathname;
36
+ return dataService.fetchData(pathOptions, res.routerOptions, res.locals)
40
37
  .then(function formatResult(result) {
41
- const response = _.pick(result, ['posts', 'meta']);
42
-
43
- response.title = getTitle(result.data);
44
- response.description = settingsCache.get('description');
45
-
46
- return response;
47
- })
38
+ const response = lodash_1.default.pick(result, ['posts', 'meta']);
39
+ response.title = getTitle(result.data);
40
+ response.description = settingsCache.get('description');
41
+ return response;
42
+ })
48
43
  .then(function (data) {
49
- return rssService.render(res, baseUrl, data);
50
- })
44
+ return rssService.render(res, baseUrl, data);
45
+ })
51
46
  .catch(renderer.handleError(next));
52
- };
47
+ }
@@ -0,0 +1,66 @@
1
+ import type {Request, Response, NextFunction} from 'express';
2
+ import _ from 'lodash';
3
+ import url from 'node:url';
4
+
5
+ const debug = require('@tryghost/debug')('services:routing:controllers:rss');
6
+ const security = require('@tryghost/security');
7
+ const settingsCache = require('../../../../shared/settings-cache');
8
+ const rssService = require('../../rss');
9
+ const renderer = require('../../rendering');
10
+ const dataService = require('../../data');
11
+
12
+ export interface RSSPathOptions {
13
+ page: number;
14
+ slug?: string;
15
+ }
16
+
17
+ export interface RSSResponse extends Response {
18
+ routerOptions: Record<string, unknown>;
19
+ }
20
+
21
+ export interface RelatedData {
22
+ author?: Array<{name: string}>;
23
+ tag?: Array<{name: string}>;
24
+ [key: string]: unknown;
25
+ }
26
+
27
+ /**
28
+ * Generates the title for the RSS feed based on author, tag, or publication settings.
29
+ */
30
+ function getTitle(relatedData?: RelatedData): string {
31
+ const data = relatedData || {};
32
+ let titleStart = _.get(data, 'author[0].name') || _.get(data, 'tag[0].name') || '';
33
+
34
+ titleStart += titleStart ? ' - ' : '';
35
+ return titleStart + settingsCache.get('title');
36
+ }
37
+
38
+ /**
39
+ * RSS routing controller.
40
+ * Fetches posts/meta data and delegates rendering to `rssService`.
41
+ */
42
+ export function rssController(req: Request, res: RSSResponse, next: NextFunction): Promise<void> {
43
+ debug('rssController');
44
+
45
+ const pathOptions: RSSPathOptions = {
46
+ page: 1, // required for fetchData
47
+ slug: req.params.slug ? security.string.safe(req.params.slug) : undefined
48
+ };
49
+
50
+ // CASE: Ghost is using an rss cache - normalize the URL for use as a key
51
+ const baseUrl = url.parse(req.originalUrl).pathname;
52
+
53
+ return dataService.fetchData(pathOptions, res.routerOptions, res.locals)
54
+ .then(function formatResult(result: {posts?: unknown[]; meta?: unknown; data?: RelatedData}) {
55
+ const response = _.pick(result, ['posts', 'meta']) as Record<string, unknown>;
56
+
57
+ response.title = getTitle(result.data);
58
+ response.description = settingsCache.get('description');
59
+
60
+ return response;
61
+ })
62
+ .then(function (data: Record<string, unknown>) {
63
+ return rssService.render(res, baseUrl, data);
64
+ })
65
+ .catch(renderer.handleError(next));
66
+ }
@@ -1,6 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const debug = require('@tryghost/debug')('services:routing:controllers:static');
3
3
  const renderer = require('../../rendering');
4
+ const {resolveRouteData} = require('../api-adapter');
4
5
 
5
6
  function processQuery(query, locals) {
6
7
  const api = require('../../proxy').api;
@@ -35,10 +36,10 @@ function processQuery(query, locals) {
35
36
  module.exports = function staticController(req, res, next) {
36
37
  debug('staticController', res.routerOptions);
37
38
 
38
- let promises = [];
39
+ const apiCalls = resolveRouteData(res.routerOptions.data);
39
40
 
40
- _.each(res.routerOptions.data, function (query) {
41
- promises.push(processQuery(query, res.locals));
41
+ const promises = _.map(apiCalls, function (apiCall) {
42
+ return processQuery(apiCall, res.locals);
42
43
  });
43
44
 
44
45
  return Promise.all(promises)
@@ -49,13 +50,13 @@ module.exports = function staticController(req, res, next) {
49
50
  response.data = {};
50
51
 
51
52
  let resultIndex = 0;
52
- _.each(res.routerOptions.data, function (config, name) {
53
- response.data[name] = result[resultIndex][config.resource];
53
+ _.each(apiCalls, function (apiCall, name) {
54
+ response.data[name] = result[resultIndex][apiCall.resource];
54
55
 
55
- if (config.type === 'browse') {
56
+ if (apiCall.type === 'browse') {
56
57
  response.data[name].meta = result[resultIndex].meta;
57
58
  // @TODO: remove in Ghost 3.0 (see https://github.com/TryGhost/Ghost/issues/10434)
58
- response.data[name][config.resource] = result[resultIndex][config.resource];
59
+ response.data[name][apiCall.resource] = result[resultIndex][apiCall.resource];
59
60
  }
60
61
 
61
62
  resultIndex = resultIndex + 1;
@@ -1,12 +1,26 @@
1
1
  const EventEmitter = require('events').EventEmitter;
2
2
 
3
3
  /**
4
- * Frontend-internal routing events.
4
+ * Raised for each router mounted during activation.
5
5
  *
6
- * Carries `router.created` and `routers.reset`, which are emitted by the
7
- * router manager and consumed only inside the frontend (the sitemap keeps
8
- * its route entries in sync from them). They used to ride the server's
9
- * shared event bus purely for historical reasons nothing server-side
10
- * listens to them.
6
+ * @typedef {Object} RouteRegistered
7
+ * @property {string|null} path - route in domain notation, e.g. `/about/`.
8
+ * Null for routers with no route of their own: the static pages router,
9
+ * and taxonomies, which have no index route (`/tag/` does not exist).
10
+ * @property {string} type - the kind of router, e.g. `CollectionRouter`
11
+ * @property {string} id - the router's identifier
12
+ */
13
+
14
+ /**
15
+ * Frontend-internal routing domain events.
16
+ *
17
+ * Carries `RouteRegistered` and `RoutesReset` — the latter has no payload and
18
+ * is raised before a reload clears the routers. Both are emitted by the router
19
+ * manager and consumed only inside the frontend (the sitemap keeps its route
20
+ * entries in sync from them). They used to ride the server's shared event bus
21
+ * purely for historical reasons — nothing server-side listens to them.
22
+ *
23
+ * The payloads are plain data, so a consumer never depends on the internals
24
+ * of the Express-backed router that happened to raise the event.
11
25
  */
12
26
  module.exports = new EventEmitter();
@@ -13,6 +13,7 @@ const express = require('../../../shared/express');
13
13
  const _ = require('lodash');
14
14
  const url = require('url');
15
15
  const security = require('@tryghost/security');
16
+ const {resolveResourceRead} = require('./api-adapter');
16
17
  const urlUtils = require('../../../shared/url-utils').default;
17
18
  const registry = require('./registry');
18
19
 
@@ -197,6 +198,11 @@ class ParentRouter {
197
198
 
198
199
  /**
199
200
  * @description Figure out if the router has a redirect enabled.
201
+ *
202
+ * A route claims a resource by reading it: `data: tag.bacon` on this router
203
+ * means /tag/bacon/ should redirect here from wherever else it lives. Only
204
+ * `read` entries claim a slug, and an entry can opt out with `redirect: false`.
205
+ *
200
206
  * @param {string} routerType
201
207
  * @param {string} slug
202
208
  * @returns {boolean}
@@ -204,14 +210,21 @@ class ParentRouter {
204
210
  isRedirectEnabled(routerType, slug) {
205
211
  debug('isRedirectEnabled', this.name, this.route && this.route.value, routerType, slug);
206
212
 
207
- if (!this.data || !Object.keys(this.data.router)) {
213
+ if (!this.data) {
208
214
  return false;
209
215
  }
210
216
 
211
- return _.find(this.data.router, function (entries, type) {
212
- if (routerType === type) {
213
- return _.find(entries, {redirect: true, slug: slug});
217
+ // Top-level shorthand (`data: tag.bacon`) is a single unnamed entry.
218
+ const entries = typeof this.data === 'string' ? [this.data] : Object.values(this.data);
219
+
220
+ return entries.some((entry) => {
221
+ if (typeof entry !== 'string' && entry.redirect === false) {
222
+ return false;
214
223
  }
224
+
225
+ const read = resolveResourceRead(entry);
226
+
227
+ return !!read && read.resource === routerType && read.slug === slug;
215
228
  });
216
229
  }
217
230
 
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toExpressNotation = toExpressNotation;
4
+ /**
5
+ * Convert a domain-model permalink into Express / URL-service notation.
6
+ *
7
+ * @example toExpressNotation('/{slug}/') // => '/:slug/'
8
+ * @example toExpressNotation('/{primary_tag}/{slug}/') // => '/:primary_tag/:slug/'
9
+ * @example toExpressNotation('/:slug/') // => '/:slug/' (idempotent)
10
+ */
11
+ function toExpressNotation(permalink) {
12
+ return permalink.replace(/{(\w+)}/g, ':$1');
13
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Convert a domain-model permalink into Express / URL-service notation.
3
+ *
4
+ * @example toExpressNotation('/{slug}/') // => '/:slug/'
5
+ * @example toExpressNotation('/{primary_tag}/{slug}/') // => '/:primary_tag/:slug/'
6
+ * @example toExpressNotation('/:slug/') // => '/:slug/' (idempotent)
7
+ */
8
+ export function toExpressNotation(permalink: string): string {
9
+ return permalink.replace(/{(\w+)}/g, ':$1');
10
+ }
@@ -1,58 +1,82 @@
1
1
  const _ = require('lodash');
2
- let routes = [];
3
- let routers = {};
4
2
 
5
3
  /**
6
- * @description The router registry is helpful for debugging purposes and let's you search existing routes and routers.
4
+ * Every registered router is a Ghost router `ParentRouter` itself (the site
5
+ * and apps routers) or one of its subclasses (Collection, StaticRoutes,
6
+ * Taxonomy, StaticPages, Preview, Email, Unsubscribe). They wrap an Express
7
+ * router, reachable via `.router()`, but are not one themselves: the registry's
8
+ * own lookups read Ghost-side members (`.name`, `.routerName`, `.reset()`,
9
+ * `.getRssUrl()`) that an Express router does not have.
10
+ *
11
+ * Type-only import — no runtime require, so this does not close a cycle with
12
+ * `parent-router.js`, which requires this module.
13
+ *
14
+ * @typedef {import('./parent-router')} ParentRouter
7
15
  */
8
- module.exports = {
16
+
17
+ /**
18
+ * @description The router registry is helpful for debugging purposes and lets you search existing routes and routers.
19
+ *
20
+ * Exported as a single shared instance so that every consumer
21
+ * (`routing/index.js`, `parent-router.js`) operates on the same registry, the
22
+ * same way the previous module-level state did — just held on an instance
23
+ * rather than in module-scoped `let` variables.
24
+ */
25
+ class Registry {
26
+ constructor() {
27
+ /** @type {Array<{route: string, from: string}>} */
28
+ this.routes = [];
29
+ /** @type {Object<string, ParentRouter>} */
30
+ this.routers = {};
31
+ }
32
+
9
33
  /**
10
- * @description Get's called if you register a url pattern in express.
34
+ * @description Gets called if you register a url pattern in express.
11
35
  * @param {string} routerName
12
36
  * @param {string} route
13
37
  */
14
38
  setRoute(routerName, route) {
15
- routes.push({route: route, from: routerName});
16
- },
39
+ this.routes.push({route: route, from: routerName});
40
+ }
17
41
 
18
42
  /**
19
- * @description Get's called if you register a router in express.
43
+ * @description Gets called if you register a router in express.
20
44
  * @param {string} name
21
- * @param {import('express').Router} router
45
+ * @param {ParentRouter} router
22
46
  */
23
47
  setRouter(name, router) {
24
- routers[name] = router;
25
- },
48
+ this.routers[name] = router;
49
+ }
26
50
 
27
51
  /**
28
52
  * @description Get all registered routes.
29
- * @returns {Array}
53
+ * @returns {Array<{route: string, from: string}>}
30
54
  */
31
55
  getAllRoutes() {
32
- return _.cloneDeep(routes);
33
- },
56
+ return _.cloneDeep(this.routes);
57
+ }
34
58
 
35
59
  /**
36
60
  * @description Get router by name.
37
61
  * @param {string} name
38
- * @returns {import('express').Router}
62
+ * @returns {ParentRouter|undefined}
39
63
  */
40
64
  getRouter(name) {
41
- return routers[name];
42
- },
65
+ return this.routers[name];
66
+ }
43
67
 
44
68
  /**
45
- * Gets a router by it's internal router name
69
+ * Gets a router by its internal router name
46
70
  * @param {string} name internal router name
47
- * @returns {import('express').Router}
71
+ * @returns {ParentRouter|undefined}
48
72
  */
49
73
  getRouterByName(name) {
50
- for (let routerKey in routers) {
51
- if (routers[routerKey].name === name) {
52
- return routers[routerKey];
74
+ for (let routerKey in this.routers) {
75
+ if (this.routers[routerKey].name === name) {
76
+ return this.routers[routerKey];
53
77
  }
54
78
  }
55
- },
79
+ }
56
80
 
57
81
  /**
58
82
  *
@@ -77,7 +101,7 @@ module.exports = {
77
101
  getRssUrl(options) {
78
102
  let rssUrl = null;
79
103
 
80
- const collectionIndexRouter = _.find(routers, {name: 'CollectionRouter', routerName: 'index'});
104
+ const collectionIndexRouter = _.find(this.routers, {name: 'CollectionRouter', routerName: 'index'});
81
105
 
82
106
  if (collectionIndexRouter) {
83
107
  rssUrl = collectionIndexRouter.getRssUrl(options);
@@ -88,7 +112,7 @@ module.exports = {
88
112
  }
89
113
  }
90
114
 
91
- const collectionRouters = _.filter(routers, {name: 'CollectionRouter'});
115
+ const collectionRouters = _.filter(this.routers, {name: 'CollectionRouter'});
92
116
 
93
117
  if (collectionRouters && collectionRouters.length === 1) {
94
118
  rssUrl = collectionRouters[0].getRssUrl(options);
@@ -108,32 +132,34 @@ module.exports = {
108
132
  }
109
133
 
110
134
  return rssUrl;
111
- },
135
+ }
112
136
 
113
137
  /**
114
138
  * @description Reset all routes.
115
139
  */
116
140
  resetAllRoutes() {
117
- routes = [];
118
- },
141
+ this.routes = [];
142
+ }
119
143
 
120
144
  /**
121
145
  * @description Reset all routers.
122
146
  */
123
147
  resetAllRouters() {
124
- _.each(routers, (value) => {
148
+ _.each(this.routers, (value) => {
125
149
  if (value && typeof value.reset === 'function') {
126
150
  value.reset();
127
151
  }
128
152
  });
129
153
 
130
- routers = {};
131
- },
154
+ this.routers = {};
155
+ }
132
156
 
133
157
  /**
134
158
  * @description Clear all routers (for testing).
135
159
  */
136
160
  clearAllRouters() {
137
- routers = {};
161
+ this.routers = {};
138
162
  }
139
- };
163
+ }
164
+
165
+ module.exports = new Registry();
@@ -8,7 +8,7 @@ const ParentRouter = require('./parent-router');
8
8
  const EmailRouter = require('./email-router');
9
9
  const UnsubscribeRouter = require('./unsubscribe-router');
10
10
 
11
- // Frontend-internal routing events (router.created / routers.reset)
11
+ // Frontend-internal routing domain events (RouteRegistered / RoutesReset)
12
12
  const routingEvents = require('./events');
13
13
 
14
14
  class RouterManager {
@@ -16,7 +16,7 @@ class RouterManager {
16
16
  this.registry = registry;
17
17
  this.siteRouter = null;
18
18
  /**
19
- * @type {URLServiceFacade}
19
+ * @type {UrlService}
20
20
  */
21
21
  this.urlService = null;
22
22
  }
@@ -30,11 +30,17 @@ class RouterManager {
30
30
  }
31
31
 
32
32
  routerCreated(router) {
33
- routingEvents.emit('router.created', router);
33
+ routingEvents.emit('RouteRegistered', {
34
+ // Not every router owns a route: the static pages router has none,
35
+ // and taxonomies have no index route (`/tag/` does not exist).
36
+ path: router.route ? router.route.value : null,
37
+ type: router.name,
38
+ id: router.identifier
39
+ });
34
40
 
35
41
  // CASE: there are router types which do not generate resource urls
36
- // e.g. static route router, in this case we don't want ot notify the URL service
37
- if (!router || !router.getPermalinks()) {
42
+ // e.g. static route router, in this case we don't want to notify the URL service
43
+ if (!router.getPermalinks()) {
38
44
  return;
39
45
  }
40
46
 
@@ -65,7 +71,7 @@ class RouterManager {
65
71
  this.registry.resetAllRouters();
66
72
  this.registry.resetAllRoutes();
67
73
 
68
- routingEvents.emit('routers.reset');
74
+ routingEvents.emit('RoutesReset');
69
75
 
70
76
  this.siteRouter = new ParentRouter('SiteRouter');
71
77
  this.registry.setRouter('siteRouter', this.siteRouter);
@@ -90,10 +96,10 @@ class RouterManager {
90
96
  * 5. Static Pages: Weaker than collections, because we first try to find a post slug and fallback to lookup a static page.
91
97
  * 6. Internal Apps: Weakest
92
98
  *
93
- * @param {object} routerSettings
99
+ * @param {RouteSettings} routeSettings
94
100
  */
95
- start(routerSettings) {
96
- debug('routing start', routerSettings);
101
+ start(routeSettings) {
102
+ debug('routing start', routeSettings);
97
103
  const RESOURCE_CONFIG = require(`./config`);
98
104
 
99
105
  const unsubscribeRouter = new UnsubscribeRouter();
@@ -110,14 +116,14 @@ class RouterManager {
110
116
  this.siteRouter.mountRouter(previewRouter.router());
111
117
  this.registry.setRouter('previewRouter', previewRouter);
112
118
 
113
- for (const route of routerSettings.routes) {
119
+ for (const route of routeSettings.routes) {
114
120
  const staticRoutesRouter = new StaticRoutesRouter(route.path, route, this.routerCreated.bind(this));
115
121
  this.siteRouter.mountRouter(staticRoutesRouter.router());
116
122
 
117
123
  this.registry.setRouter(staticRoutesRouter.identifier, staticRoutesRouter);
118
124
  }
119
125
 
120
- for (const collection of routerSettings.collections) {
126
+ for (const collection of routeSettings.collections) {
121
127
  const collectionRouter = new CollectionRouter(collection.path, collection, RESOURCE_CONFIG, this.routerCreated.bind(this));
122
128
  this.siteRouter.mountRouter(collectionRouter.router());
123
129
  this.registry.setRouter(collectionRouter.identifier, collectionRouter);
@@ -128,8 +134,8 @@ class RouterManager {
128
134
 
129
135
  this.registry.setRouter('staticPagesRouter', staticPagesRouter);
130
136
 
131
- for (const taxonomy of routerSettings.taxonomies) {
132
- const taxonomyRouter = new TaxonomyRouter(taxonomy.key, taxonomy.permalink, RESOURCE_CONFIG, this.routerCreated.bind(this));
137
+ for (const [key, permalink] of Object.entries(routeSettings.taxonomies)) {
138
+ const taxonomyRouter = new TaxonomyRouter(key, permalink, RESOURCE_CONFIG, this.routerCreated.bind(this));
133
139
  this.siteRouter.mountRouter(taxonomyRouter.router());
134
140
 
135
141
  this.registry.setRouter(taxonomyRouter.identifier, taxonomyRouter);
@@ -171,7 +177,7 @@ class RouterManager {
171
177
  if (collectionRouter && collectionRouter.getPermalinks().getValue().match(/:year|:month|:day/)) {
172
178
  debug('handleTimezoneEdit: trigger regeneration');
173
179
 
174
- this.urlService.onRouterUpdated(collectionRouter.identifier);
180
+ this.urlService.onRouterUpdated();
175
181
  }
176
182
  }
177
183
  }
@@ -180,20 +186,16 @@ module.exports = RouterManager;
180
186
 
181
187
  /**
182
188
  * @typedef {Object} RouterConfig
183
- * @property {RouteSettings} [routeSettings] - JSON config representing routes
184
- * @property {URLServiceFacade} urlService - resource-based URL service facade
189
+ * @property {RouteSettings} [routeSettings] - parsed route settings domain model
190
+ * @property {UrlService} urlService - resource-based URL service
185
191
  */
186
192
 
187
193
  /**
188
- * The shape RouterManager consumes — produced by the activation bridge. This is
189
- * a temporary reference into server code; when the bridge is removed (HKG-1898)
190
- * it becomes the domain `RouteSettings` from @tryghost/adapter-base-route-settings.
191
- *
192
- * @typedef {import('../../../server/services/route-settings/activation-bridge').RouterSettings} RouteSettings
194
+ * @typedef {import('@tryghost/adapter-base-route-settings').RouteSettings} RouteSettings
193
195
  */
194
196
 
195
197
  /**
196
- * @typedef {Object} URLServiceFacade
198
+ * @typedef {Object} UrlService
197
199
  * @property {Function} getUrlForResource
198
200
  * @property {Function} ownsResource
199
201
  * @property {Function} resolveUrl
@@ -15,7 +15,7 @@ class StaticRoutesRouter extends ParentRouter {
15
15
 
16
16
  this.route = {value: mainRoute};
17
17
  this.templates = object.templates || [];
18
- this.data = object.data || {query: {}, router: {}};
18
+ this.data = object.data || {};
19
19
  this.routerName = mainRoute === '/' ? 'index' : mainRoute.replace(/\//g, '');
20
20
  this.routerCreated = routerCreated;
21
21
 
@@ -80,7 +80,7 @@ class StaticRoutesRouter extends ParentRouter {
80
80
  filter: this.filter,
81
81
  limit: this.limit,
82
82
  order: this.order,
83
- data: this.data.query,
83
+ data: this.data,
84
84
  templates: this.templates
85
85
  };
86
86
 
@@ -117,7 +117,7 @@ class StaticRoutesRouter extends ParentRouter {
117
117
  message: `Missing template ${res.routerOptions.templates.map(x => `${x}.hbs`).join(', ')} for route "${req.originalUrl}".`
118
118
  });
119
119
  },
120
- data: this.data.query,
120
+ data: this.data,
121
121
  context: [this.routerName],
122
122
  contentType: this.contentType
123
123
  };
@@ -131,7 +131,7 @@ class StaticRoutesRouter extends ParentRouter {
131
131
  * @returns {boolean}
132
132
  */
133
133
  isChannel(object) {
134
- // buildRouterSettings always sets `type` ('channel' | 'template') on
134
+ // parseRouteSettings always sets `type` ('channel' | 'template') on
135
135
  // every route, so a channel is simply `type === 'channel'`.
136
136
  return object?.type === 'channel';
137
137
  }
@@ -5,6 +5,7 @@ const RSSRouter = require('./rss-router');
5
5
  const urlUtils = require('../../../shared/url-utils').default;
6
6
  const controllers = require('./controllers');
7
7
  const middleware = require('./middleware');
8
+ const {toExpressNotation} = require('./permalink-adapter');
8
9
 
9
10
  /**
10
11
  * @description Taxonomies are groupings of posts based on a common relation.
@@ -17,8 +18,9 @@ class TaxonomyRouter extends ParentRouter {
17
18
  this.taxonomyKey = key;
18
19
  this.RESOURCE_CONFIG = RESOURCE_CONFIG;
19
20
 
21
+ // convert domain `{slug}` -> Express/URL-service `:slug` at this boundary
20
22
  this.permalinks = {
21
- value: permalinks
23
+ value: toExpressNotation(permalinks)
22
24
  };
23
25
 
24
26
  this.permalinks.getValue = () => {
@@ -74,7 +76,9 @@ class TaxonomyRouter extends ParentRouter {
74
76
  type: 'channel',
75
77
  name: this.taxonomyKey,
76
78
  permalinks: this.permalinks.getValue(),
77
- data: {[this.taxonomyKey]: this.RESOURCE_CONFIG.QUERY[this.taxonomyKey]},
79
+ // Route data in domain form — the API adapter resolves it to a
80
+ // controller call, and fetch-data fills `%s` in from the request.
81
+ data: {[this.taxonomyKey]: {type: 'read', resource: this.getResourceType(), slug: '%s'}},
78
82
  filter: this.RESOURCE_CONFIG.TAXONOMIES[this.taxonomyKey].filter,
79
83
  resourceType: this.getResourceType(),
80
84
  context: [this.taxonomyKey],