ghost 6.56.0 → 6.57.1

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 (428) 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-adapter-base-scheduling-0.2.1.tgz +0 -0
  5. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  6. package/components/tryghost-kg-converters-1.2.4.tgz +0 -0
  7. package/components/tryghost-kg-default-cards-10.3.4.tgz +0 -0
  8. package/components/tryghost-kg-default-nodes-2.1.5.tgz +0 -0
  9. package/components/tryghost-kg-default-transforms-1.3.3.tgz +0 -0
  10. package/components/tryghost-kg-html-to-lexical-1.3.3.tgz +0 -0
  11. package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
  12. package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
  13. package/core/app.js +1 -1
  14. package/core/boot.js +21 -25
  15. package/core/bridge.js +10 -12
  16. package/core/built/admin/assets/Combination-BDvCdg1t.js +41 -0
  17. package/core/built/admin/assets/about-BNojRaxf.js +1 -0
  18. package/core/built/admin/assets/{account-migration-D3O_yVck.js → account-migration-DMS8JsM-.js} +1 -1
  19. package/core/built/admin/assets/action-list-lGzZLHc8.js +1 -0
  20. package/core/built/admin/assets/activitypub/{account-migration-D8FbP-Z-.js → account-migration-DHFbePl6.js} +7 -7
  21. package/core/built/admin/assets/activitypub/activitypub.js +3 -3
  22. package/core/built/admin/assets/activitypub/{avatar-11EA1VSs.js → avatar-CT4tS2_S.js} +2 -2
  23. package/core/built/admin/assets/activitypub/{avatar-flipboard-jfbLG-xe.js → avatar-flipboard-ByYWKipo.js} +2 -2
  24. package/core/built/admin/assets/activitypub/{bluesky-sharing-f1jTQe2P.js → bluesky-sharing-srVnSHDz.js} +8 -8
  25. package/core/built/admin/assets/activitypub/{content-formatters-nmTOPY9M.js → content-formatters-C2sos5Ht.js} +3 -3
  26. package/core/built/admin/assets/activitypub/{copy-BCwo9ep3.js → copy-B1UBTOoZ.js} +2 -2
  27. package/core/built/admin/assets/activitypub/{dist-BEfX-0aW.js → dist-MPsb2WZ1.js} +4 -4
  28. package/core/built/admin/assets/activitypub/{domain-AaDlZlrA.js → domain-DzcM9Dzo.js} +9 -9
  29. package/core/built/admin/assets/activitypub/{edit-profile-DPi8Tl5M.js → edit-profile-CsQ_4xAk.js} +5 -5
  30. package/core/built/admin/assets/activitypub/{explore-CxTzjILQ.js → explore-CJe0DZBK.js} +8 -8
  31. package/core/built/admin/assets/activitypub/{feed-DPv5x2MX.js → feed-CKV3qWON.js} +9 -9
  32. package/core/built/admin/assets/activitypub/{field-DbgA8lat.js → field-DckHfDJf.js} +3 -3
  33. package/core/built/admin/assets/activitypub/{hash-BWuZoYkA.js → hash-Dlp8RM55.js} +2 -2
  34. package/core/built/admin/assets/activitypub/{inbox-35VDQ2K2.js → inbox-CsPy4R0M.js} +2 -2
  35. package/core/built/admin/assets/activitypub/{inbox-DSrF_i1O.js → inbox-DAsjzUUe.js} +10 -10
  36. package/core/built/admin/assets/activitypub/{label-CPjFBbo7.js → label-DWyo9E5T.js} +3 -3
  37. package/core/built/admin/assets/activitypub/layout-DM_3pqsU.js +1 -0
  38. package/core/built/admin/assets/activitypub/{moderation-BkDC1XVZ.js → moderation-B0Inc03M.js} +7 -7
  39. package/core/built/admin/assets/activitypub/{note-xEyH4xT-.js → note-CSE54lER.js} +7 -7
  40. package/core/built/admin/assets/activitypub/{notifications-DClaL3ui.js → notifications-RSwbKqdh.js} +9 -9
  41. package/core/built/admin/assets/activitypub/{preferences-DpnOa-4Z.js → preferences-CE231n2_.js} +11 -11
  42. package/core/built/admin/assets/activitypub/{profile-Dvi9mz-6.js → profile-aaQ1j1Eo.js} +13 -13
  43. package/core/built/admin/assets/activitypub/{reply-Cs9ySd6Z.js → reply-Cjb0Vs3m.js} +2 -2
  44. package/core/built/admin/assets/activitypub/{routes-DFBeTnfn.js → routes-Djb0mc9k.js} +26 -26
  45. package/core/built/admin/assets/activitypub/{separator-C5u_VjzY.js → separator-D8pROI5n.js} +3 -3
  46. package/core/built/admin/assets/activitypub/{settings-CV2fFu6D.js → settings-DMc32IQl.js} +5 -5
  47. package/core/built/admin/assets/activitypub/{site-_TgDd_EM.js → site-DVIcsohX.js} +4 -4
  48. package/core/built/admin/assets/activitypub/{step-1-BfnNL2oF.js → step-1-9Yey9usF.js} +5 -5
  49. package/core/built/admin/assets/activitypub/{step-2-DLndZkO-.js → step-2-DdYmKRXV.js} +6 -6
  50. package/core/built/admin/assets/activitypub/{step-3-A-PZTtRE.js → step-3-hdSkcjZU.js} +10 -10
  51. package/core/built/admin/assets/activitypub/{tabs-BUbz7tea.js → tabs-CUqseYzQ.js} +6 -6
  52. package/core/built/admin/assets/activitypub/{topic-filter-BdX_xYYT.js → topic-filter-Coni6OXM.js} +3 -3
  53. package/core/built/admin/assets/activitypub/{use-activity-pub-queries-EwuRemHh.js → use-activity-pub-queries-MeHTPMQv.js} +2 -2
  54. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-cy4ACBc4.js → use-navigate-with-base-path-B046AM38.js} +24 -7
  55. package/core/built/admin/assets/activitypub/{use-reply-chain-data-CyFcGfan.js → use-reply-chain-data-1AO-Xob6.js} +5 -5
  56. package/core/built/admin/assets/activitypub/{x-7zk8mV2p.js → x-BRfRYd16.js} +2 -2
  57. package/core/built/admin/assets/add-integration-modal-DU9ghGLS.js +1 -0
  58. package/core/built/admin/assets/add-newsletter-modal-DFxuQrYu.js +1 -0
  59. package/core/built/admin/assets/add-recommendation-modal-D-3LOrdd.js +1 -0
  60. package/core/built/admin/assets/analytics-DTIMRhWw.js +1 -0
  61. package/core/built/admin/assets/announcement-bar-modal-DGCcezB6.js +1 -0
  62. package/core/built/admin/assets/api-keys-Dx4NeNpK.js +1 -0
  63. package/core/built/admin/assets/api-keys-_iCT4dxr.js +1 -0
  64. package/core/built/admin/assets/{audience-CkBb2LlO.js → audience-DkknNqhZ.js} +1 -1
  65. package/core/built/admin/assets/automated-emails-PayPCT8L.js +1 -0
  66. package/core/built/admin/assets/{automations-DhKeS_U5.js → automations-162q5HjL.js} +1 -1
  67. package/core/built/admin/assets/{automations-cMllU545.js → automations-DvSU7QhW.js} +1 -1
  68. package/core/built/admin/assets/{bluesky-sharing-DPGpyD-G.js → bluesky-sharing-yZ9A_jL8.js} +1 -1
  69. package/core/built/admin/assets/brand-icon-09YqFZjV.js +1 -0
  70. package/core/built/admin/assets/{breadcrumb-DIfcF5ow.js → breadcrumb-CjOH7LCU.js} +1 -1
  71. package/core/built/admin/assets/{chart-helpers-DV0FkdcD.js → chart-helpers-DGxvWnBT.js} +1 -1
  72. package/core/built/admin/assets/checkbox-BSUcnNq_.js +1 -0
  73. package/core/built/admin/assets/{chunk.332.05991a101d67f732dec3.js → chunk.424.4a27628efdade15c2dab.js} +28 -27
  74. package/core/built/admin/assets/chunk.524.dce1c51e0bc30fb2718e.js +25 -0
  75. package/core/built/admin/assets/{chunk.211.6f7328d63c41536451b3.js → chunk.571.40f093ed6d883993714e.js} +5 -5
  76. package/core/built/admin/assets/chunk.582.3a430d5c6a744fd475b6.js +27 -0
  77. package/core/built/admin/assets/code-editor-view-BcyKABrG.js +1 -0
  78. package/core/built/admin/assets/color-picker-field-8NoSnhNI.js +1 -0
  79. package/core/built/admin/assets/color-utils-Dzeeuj1F.js +1 -0
  80. package/core/built/admin/assets/combobox-5rdgDrDV.js +1 -0
  81. package/core/built/admin/assets/command-BOYMbZa_.js +1 -0
  82. package/core/built/admin/assets/comments-BhNM5CYl.js +1 -0
  83. package/core/built/admin/assets/components-CwL6a6As-B0E0-NBJ.js +1 -0
  84. package/core/built/admin/assets/confirmation-modal-CYD7x3UQ.js +1 -0
  85. package/core/built/admin/assets/content-api-modal-BtW4Z1-1.js +1 -0
  86. package/core/built/admin/assets/copy-field-CEp_XieW.js +1 -0
  87. package/core/built/admin/assets/currency-Dy4Tc2R2.js +1 -0
  88. package/core/built/admin/assets/custom-integration-modal-bk3lNEuQ.js +1 -0
  89. package/core/built/admin/assets/{date-range-select-dXc-GsVe.js → date-range-select-B3Ij1Rqg.js} +1 -1
  90. package/core/built/admin/assets/debounce-Cx5B_9OI.js +3 -0
  91. package/core/built/admin/assets/design-and-theme-modal-B2xYKS1I.js +23 -0
  92. package/core/built/admin/assets/dirty-confirm-dialog-YE9L21gY.js +1 -0
  93. package/core/built/admin/assets/disabled-sources-indicator-uIzbWL7K.js +1 -0
  94. package/core/built/admin/assets/{dist-pHiOxyxa.js → dist-ARN6XTcR.js} +1 -1
  95. package/core/built/admin/assets/dist-B2PvRwLn.js +1 -0
  96. package/core/built/admin/assets/{dist-DyViJwIy.js → dist-Bg8bSvLA.js} +3 -3
  97. package/core/built/admin/assets/dist-CsvXCJSe.js +23 -0
  98. package/core/built/admin/assets/dist-DlCyLrOC.js +1 -0
  99. package/core/built/admin/assets/dist-j1xxxnY8.js +1 -0
  100. package/core/built/admin/assets/dist-myQaY0ka.js +1 -0
  101. package/core/built/admin/assets/{domain-B5ogXUBa.js → domain-DzrOAPY8.js} +1 -1
  102. package/core/built/admin/assets/{dropzone-BnFG7dDP.js → dropzone-CzhP33wa.js} +1 -1
  103. package/core/built/admin/assets/{edit-profile-B07jCZy9.js → edit-profile-oufs4R4n.js} +1 -1
  104. package/core/built/admin/assets/editor-BBKrunMK.js +8 -0
  105. package/core/built/admin/assets/embed-signup-form-modal-Ch3s6lqA.js +9 -0
  106. package/core/built/admin/assets/{explore-Ca1y8HW_.js → explore-CA-R01Br.js} +1 -1
  107. package/core/built/admin/assets/{feed-x4iFMBP4.js → feed-ClC8_Gld.js} +1 -1
  108. package/core/built/admin/assets/{field-ChCAabZg.js → field-B3OPenbP.js} +1 -1
  109. package/core/built/admin/assets/{filter-sources-LdtH1e-T.js → filter-sources-CiPLnG9A.js} +1 -1
  110. package/core/built/admin/assets/filters-Bz0HsRie.js +1 -0
  111. package/core/built/admin/assets/{filters-CjVKRP8U.js → filters-yFvybRMe.js} +1 -1
  112. package/core/built/admin/assets/first-promoter-modal-BC0UpYCD.js +1 -0
  113. package/core/built/admin/assets/format-url-C-t8G6Qd.js +1 -0
  114. package/core/built/admin/assets/{ghost-7f01131115186d1af84ead76e79646dd.js → ghost-d683fbeb945b13155ea669caa5d8db41.js} +300 -298
  115. package/core/built/admin/assets/{gift-link-modal-Buqh2vXh.js → gift-link-modal-BKRuqo-k.js} +1 -1
  116. package/core/built/admin/assets/{gift-links-CsUhefWG.js → gift-links-CVuqLhsZ.js} +1 -1
  117. package/core/built/admin/assets/global-data-provider-RzW6Bnlf.js +1 -0
  118. package/core/built/admin/assets/grid-CUciBfjf.js +1 -0
  119. package/core/built/admin/assets/{growth-DajOBdN0.js → growth-ClNAldfL.js} +1 -1
  120. package/core/built/admin/assets/{growth-Dy2UOSay.js → growth-Dz8OSG06.js} +2 -2
  121. package/core/built/admin/assets/history-modal-DIVuQ5Ct.js +1 -0
  122. package/core/built/admin/assets/{hooks-CixO01lL.js → hooks-D6EE7BIt.js} +2 -2
  123. package/core/built/admin/assets/html-field-CVZ2sMxw.js +1 -0
  124. package/core/built/admin/assets/iframe-buffering-e8vH4-Qn.js +1 -0
  125. package/core/built/admin/assets/images-Ok8FFJ3A.js +1 -0
  126. package/core/built/admin/assets/{inbox-BUOLDoji.js → inbox-CMUVI6qb.js} +13 -13
  127. package/core/built/admin/assets/index-DUXM0NlS.js +67 -0
  128. package/core/built/admin/assets/index-Ds2iUoF6.css +1 -0
  129. package/core/built/admin/assets/index.es-B9tvf-t4.js +1 -0
  130. package/core/built/admin/assets/{input-group-uSK3XT7b.js → input-group-2XU-iuh_.js} +1 -1
  131. package/core/built/admin/assets/integration-header-B4DyXV06.js +1 -0
  132. package/core/built/admin/assets/integrations-BT6_iJvu.js +1 -0
  133. package/core/built/admin/assets/invite-user-modal-DrZ7xxrZ.js +1 -0
  134. package/core/built/admin/assets/isEmail-BOfC647y.js +1 -0
  135. package/core/built/admin/assets/koenig-editor-base-BPj4S760.js +1 -0
  136. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +9254 -9251
  137. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +124 -124
  138. package/core/built/admin/assets/{koenig-lexical-BFc4yFed.js → koenig-lexical-Cdjv-m3_.js} +98 -98
  139. package/core/built/admin/assets/{kpi-card-CCt-qeWD.js → kpi-card-J8Mj1sDX.js} +1 -1
  140. package/core/built/admin/assets/{kpi-card-BN-E6WYX.js → kpi-card-awos0BMH.js} +1 -1
  141. package/core/built/admin/assets/{kpi-helpers-DlxTbTs4.js → kpi-helpers-SEhvH-8E.js} +1 -1
  142. package/core/built/admin/assets/{kpi-tabs-BlcUttpn.js → kpi-tabs-R6BjsKhd.js} +1 -1
  143. package/core/built/admin/assets/{label-AVrxwmsz.js → label-BMC3dzLI.js} +1 -1
  144. package/core/built/admin/assets/label-picker-Bnlru5tO.js +1 -0
  145. package/core/built/admin/assets/{labels-DAIqKed7.js → labels-DAPjKPy2.js} +1 -1
  146. package/core/built/admin/assets/layout-yR9rlvEw.js +1 -0
  147. package/core/built/admin/assets/limit-modal-COmLevuY.js +1 -0
  148. package/core/built/admin/assets/{link-helpers-D9LsDOkG.js → link-helpers-Bzkk68GD.js} +1 -1
  149. package/core/built/admin/assets/member-custom-fields-BvFKEpxJ.js +1 -0
  150. package/core/built/admin/assets/member-detail-CWdPAe3p.js +1 -0
  151. package/core/built/admin/assets/members-Bnt0ih2R.js +11 -0
  152. package/core/built/admin/assets/modal-page-BMTzFHVO.js +1 -0
  153. package/core/built/admin/assets/{moderation-CQ3urTFE.js → moderation-mPjYHgZW.js} +1 -1
  154. package/core/built/admin/assets/multi-select-combobox-CsoyHAiX.js +1 -0
  155. package/core/built/admin/assets/navigation-modal-D_c0badj.js +1 -0
  156. package/core/built/admin/assets/newsletter-DR49NyGS.js +1 -0
  157. package/core/built/admin/assets/newsletter-detail-modal-B45pL1pb.js +1 -0
  158. package/core/built/admin/assets/newsletter-emails-B-OLfrvr.js +1 -0
  159. package/core/built/admin/assets/{newsletters-vt3Ni1Ov.js → newsletters-DGs5BaKH.js} +1 -1
  160. package/core/built/admin/assets/{newsletters-BXJbJgA-.js → newsletters-Du0lzskS.js} +1 -1
  161. package/core/built/admin/assets/{note-Dk877BTv.js → note-CSVsUKBm.js} +1 -1
  162. package/core/built/admin/assets/{notifications-CPlLjPxO.js → notifications-DV9FRtDw.js} +1 -1
  163. package/core/built/admin/assets/{offers-DEniVRD5.js → offers-Um6ab71O.js} +1 -1
  164. package/core/built/admin/assets/offers-container-modal-B0hFS8nk.js +1 -0
  165. package/core/built/admin/assets/{onboarding-route-DdStOtjy.js → onboarding-route--jL5KLPD.js} +1 -1
  166. package/core/built/admin/assets/overview-B-ZPNqMo.js +1 -0
  167. package/core/built/admin/assets/overview-D96iwoJi.js +1 -0
  168. package/core/built/admin/assets/{page-header-pp4dWmOS.js → page-header-DAvDYKO9.js} +1 -1
  169. package/core/built/admin/assets/{pages-B4goRPUn.js → pages-BVMnpI2O.js} +1 -1
  170. package/core/built/admin/assets/pintura-modal-jiUCxX0Q.js +1 -0
  171. package/core/built/admin/assets/portal-frame-D4D4nEO6.js +1 -0
  172. package/core/built/admin/assets/portal-modal-BLFdYeDH.js +1 -0
  173. package/core/built/admin/assets/{post-analytics-BMJrI81R.js → post-analytics-BhAtiFJp.js} +1 -1
  174. package/core/built/admin/assets/post-analytics-header-DK27VjJm.js +1 -0
  175. package/core/built/admin/assets/{post-analytics-provider-Btml5vJI.js → post-analytics-provider-DGg0FUqs.js} +1 -1
  176. package/core/built/admin/assets/{post-share-modal-AcUZkbfL.js → post-share-modal-DtFAC132.js} +1 -1
  177. package/core/built/admin/assets/{posts-DhXE7b6r.js → posts-CxG7v0-M.js} +1 -1
  178. package/core/built/admin/assets/preferences-CuWLISHa.js +5 -0
  179. package/core/built/admin/assets/preview-chrome-BOVO6_PE.js +1 -0
  180. package/core/built/admin/assets/preview-modal-DctYx20m.js +1 -0
  181. package/core/built/admin/assets/profile-BsKYYtuL.js +1 -0
  182. package/core/built/admin/assets/radio-group-CI5_Kf_d.js +1 -0
  183. package/core/built/admin/assets/{referrers-pmJT4k3-.js → referrers-B9QDAfYm.js} +1 -1
  184. package/core/built/admin/assets/{router-provider-BmEZf6c6.js → router-provider-DSQfprxH.js} +1 -1
  185. package/core/built/admin/assets/select-CkXqNJDJ.js +1 -0
  186. package/core/built/admin/assets/settings-B4vM-rgV.js +4 -0
  187. package/core/built/admin/assets/{settings-BGgk7oCI.js → settings-ZCj-W56o.js} +1 -1
  188. package/core/built/admin/assets/settings-breadcrumbs-DIq31FwA.js +1 -0
  189. package/core/built/admin/assets/{share-modal-BeuydaBf.js → share-modal-BNj14g79.js} +1 -1
  190. package/core/built/admin/assets/slack-modal-C6SpMQ-q.js +1 -0
  191. package/core/built/admin/assets/social-urls-CHQ9cTAK.js +1 -0
  192. package/core/built/admin/assets/{sort-button-Df4t2AL8.js → sort-button-B-k54ow2.js} +1 -1
  193. package/core/built/admin/assets/{source-icon-ajoaKb41.js → source-icon-Cej3sZM6.js} +1 -1
  194. package/core/built/admin/assets/{stats-C_lfxZAw.js → stats-B2KW8E2y.js} +1 -1
  195. package/core/built/admin/assets/{stats-view-Cxot1iD8.js → stats-view-CVzU2-p5.js} +1 -1
  196. package/core/built/admin/assets/{step-1-ogAA4lDr.js → step-1-Dbn1iIMU.js} +1 -1
  197. package/core/built/admin/assets/{step-2-C5Xini-7.js → step-2-BahnSuN6.js} +1 -1
  198. package/core/built/admin/assets/{step-3-CZv1FV81.js → step-3-CW04e2ZJ.js} +2 -2
  199. package/core/built/admin/assets/stripe-button-BkBZqaGG.js +1 -0
  200. package/core/built/admin/assets/stripe-connect-modal-CYDDrSJm.js +1 -0
  201. package/core/built/admin/assets/switch-CE2NuMn-.js +1 -0
  202. package/core/built/admin/assets/{table-DFj1wiYv.js → table-BtLcEi1M.js} +1 -1
  203. package/core/built/admin/assets/tabs-BaWRfg8j.js +1 -0
  204. package/core/built/admin/assets/tag-detail-CmqiC32L.js +1 -0
  205. package/core/built/admin/assets/tags-BbygUvNB.js +1 -0
  206. package/core/built/admin/assets/tags-BwCgmr5v.js +1 -0
  207. package/core/built/admin/assets/testimonials-modal--bdzppyh.js +1 -0
  208. package/core/built/admin/assets/tier-detail-modal-BZmAsIy4.js +1 -0
  209. package/core/built/admin/assets/{tiers-DYsa4DCo.js → tiers-Da6kxHQP.js} +1 -1
  210. package/core/built/admin/assets/toggle-group-CVl-Xigr.js +1 -0
  211. package/core/built/admin/assets/{topic-filter-DGDxDalo.js → topic-filter-BoRHRbL1.js} +1 -1
  212. package/core/built/admin/assets/transistor-modal-CBPDqEGy.js +1 -0
  213. package/core/built/admin/assets/unsplash-modal-CixoRAO2.js +1 -0
  214. package/core/built/admin/assets/{use-analytics-data-C76v4LIp.js → use-analytics-data-BiWvcf1u.js} +1 -1
  215. package/core/built/admin/assets/use-check-theme-limit-error-B14lZukR.js +2 -0
  216. package/core/built/admin/assets/use-feature-flag-BmJoc5WN.js +1 -0
  217. package/core/built/admin/assets/use-filter-params-ChoV72Hw.js +1 -0
  218. package/core/built/admin/assets/use-filterable-api-iMpDZBxD.js +1 -0
  219. package/core/built/admin/assets/use-form-vRjI0Kwk.js +1 -0
  220. package/core/built/admin/assets/{use-growth-stats-aNXJOmQr.js → use-growth-stats-Dom8xVzo.js} +1 -1
  221. package/core/built/admin/assets/use-hash-link-navigation-guard-B9j6HIrV.js +1 -0
  222. package/core/built/admin/assets/use-limiter-Dwg8ivgQ.js +2 -0
  223. package/core/built/admin/assets/use-pintura-config-Bj4QmiVk.js +1 -0
  224. package/core/built/admin/assets/use-pintura-editor-DvrslmPE.js +1 -0
  225. package/core/built/admin/assets/{use-post-referrers-CG0SZioj.js → use-post-referrers-pxIHTXFs.js} +1 -1
  226. package/core/built/admin/assets/use-query-params-DHhhu8wi.js +1 -0
  227. package/core/built/admin/assets/{use-reply-chain-data-RLdPKRmS.js → use-reply-chain-data-CmFe0N6F.js} +1 -1
  228. package/core/built/admin/assets/use-setting-group-Cmp_sy-d.js +1 -0
  229. package/core/built/admin/assets/use-settings-navigation-BmROPrls.js +1 -0
  230. package/core/built/admin/assets/{use-simple-pagination-DgcF69KI.js → use-simple-pagination-D5rL3YwO.js} +1 -1
  231. package/core/built/admin/assets/{use-tinybird-query-C1R_Kbmy.js → use-tinybird-query-DP2dMaq7.js} +1 -1
  232. package/core/built/admin/assets/{use-tinybird-token-C9fPjVM_.js → use-tinybird-token-DrK_skPQ.js} +1 -1
  233. package/core/built/admin/assets/use-url-input-ChrUZBFf.js +5 -0
  234. package/core/built/admin/assets/user-detail-modal-XODpOqNC.js +1 -0
  235. package/core/built/admin/assets/{users-Dkv8NQZe.js → users-B6hIds6n.js} +1 -1
  236. package/core/built/admin/assets/validator-Cr0sMKuW.js +7 -0
  237. package/core/built/admin/assets/{virtual-list-BmTUzeoF.js → virtual-list-Dnoafqbk.js} +1 -1
  238. package/core/built/admin/assets/web-D71mjB2r.js +1 -0
  239. package/core/built/admin/assets/web-z71lA1Y3.js +2 -0
  240. package/core/built/admin/assets/zapier-modal-Bp507Um7.js +1 -0
  241. package/core/built/admin/index.html +16 -14
  242. package/core/frontend/helpers/authors.js +1 -1
  243. package/core/frontend/helpers/link.js +3 -8
  244. package/core/frontend/helpers/tags.js +1 -1
  245. package/core/frontend/meta/author-url.js +2 -2
  246. package/core/frontend/meta/url.js +4 -4
  247. package/core/frontend/services/proxy.js +1 -1
  248. package/core/frontend/services/routing/events.js +20 -6
  249. package/core/frontend/services/routing/permalink-adapter.js +0 -13
  250. package/core/frontend/services/routing/permalink-adapter.ts +0 -13
  251. package/core/frontend/services/routing/router-manager.js +15 -9
  252. package/core/frontend/services/sitemap/base-site-map-generator.js +1 -28
  253. package/core/frontend/services/sitemap/site-map-manager.js +22 -57
  254. package/core/frontend/web/middleware/admin-toolbar.js +1 -1
  255. package/core/frontend/web/middleware/serve-indexnow-key.js +1 -7
  256. package/core/server/adapters/route-settings/utils.js +10 -2
  257. package/core/server/adapters/route-settings/utils.ts +12 -2
  258. package/core/server/api/endpoints/email-post.js +1 -1
  259. package/core/server/api/endpoints/index.js +2 -2
  260. package/core/server/api/endpoints/previews.js +1 -1
  261. package/core/server/api/endpoints/search-index-public.js +3 -3
  262. package/core/server/api/endpoints/search-index.js +4 -4
  263. package/core/server/api/endpoints/themes.js +6 -1
  264. package/core/server/api/endpoints/utils/serializers/input/authors.js +2 -2
  265. package/core/server/api/endpoints/utils/serializers/input/comments.js +1 -1
  266. package/core/server/api/endpoints/utils/serializers/input/pages.js +3 -3
  267. package/core/server/api/endpoints/utils/serializers/input/posts.js +3 -3
  268. package/core/server/api/endpoints/utils/serializers/input/tags.js +1 -1
  269. package/core/server/api/endpoints/utils/serializers/input/users.js +2 -2
  270. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +31 -13
  271. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +2 -2
  272. package/core/server/api/endpoints/utils/serializers/output/mappers/tags.js +2 -2
  273. package/core/server/api/endpoints/utils/serializers/output/mappers/users.js +8 -0
  274. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +18 -11
  275. package/core/server/data/migrations/versions/6.57/2026-08-04-18-00-00-store-custom-field-values-as-leaf-rows.js +74 -0
  276. package/core/server/data/migrations/versions/6.57/2026-08-04-18-54-14-reset-automation-email-analytics.js +25 -0
  277. package/core/server/data/schema/commands.js +21 -5
  278. package/core/server/data/schema/schema.js +24 -5
  279. package/core/server/lib/common/to-plain.ts +1 -1
  280. package/core/server/models/base/plugins/overrides.js +7 -5
  281. package/core/server/models/post.js +2 -2
  282. package/core/server/services/adapter-manager/adapter-manager.js +1 -45
  283. package/core/server/services/adapter-manager/adapter-manager.ts +2 -48
  284. package/core/server/services/adapter-manager/adapter-paths.js +28 -0
  285. package/core/server/services/adapter-manager/adapter-paths.ts +26 -0
  286. package/core/server/services/adapter-manager/base-classes.js +22 -0
  287. package/core/server/services/adapter-manager/base-classes.ts +22 -0
  288. package/core/server/services/adapter-manager/index.js +4 -27
  289. package/core/server/services/adapter-manager/index.ts +4 -31
  290. package/core/server/services/adapter-manager/utils.js +50 -0
  291. package/core/server/services/adapter-manager/utils.ts +57 -0
  292. package/core/server/services/audience-feedback/audience-feedback-controller.js +11 -2
  293. package/core/server/services/audience-feedback/audience-feedback-service.js +2 -2
  294. package/core/server/services/audience-feedback/feedback-repository.js +4 -1
  295. package/core/server/services/auth/session/session-service.js +18 -3
  296. package/core/server/services/automations/database-automations-repository.js +5 -5
  297. package/core/server/services/automations/database-automations-repository.ts +12 -12
  298. package/core/server/services/automations/database-date.js +52 -3
  299. package/core/server/services/automations/database-date.ts +23 -2
  300. package/core/server/services/automations/service.js +2 -2
  301. package/core/server/services/automations/service.ts +2 -2
  302. package/core/server/services/comments/comments-service-emails.js +1 -1
  303. package/core/server/services/comments/comments-service.js +1 -1
  304. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +12 -3
  305. package/core/server/services/email-analytics/email-analytics-service.js +4 -3
  306. package/core/server/services/email-analytics/index.js +2 -3
  307. package/core/server/services/email-analytics/index.ts +1 -2
  308. package/core/server/services/email-analytics/lib/queries.js +91 -124
  309. package/core/server/services/email-analytics/lib/queries.ts +341 -0
  310. package/core/server/services/email-service/email-service-wrapper.js +2 -1
  311. package/core/server/services/email-service/mailgun-email-provider.js +15 -0
  312. package/core/server/services/indexnow-ping/index.js +0 -2
  313. package/core/server/services/indexnow-ping/index.ts +0 -2
  314. package/core/server/services/indexnow-ping/indexnow-ping-service.js +6 -8
  315. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +9 -17
  316. package/core/server/services/lib/mailgun-client.js +3 -3
  317. package/core/server/services/media-inliner/external-media-inliner.js +12 -8
  318. package/core/server/services/member-attribution/url-translator.js +5 -7
  319. package/core/server/services/member-welcome-emails/service.js +72 -12
  320. package/core/server/services/members/api.js +1 -1
  321. package/core/server/services/members/import-export/import/completion-email.js +8 -4
  322. package/core/server/services/members/import-export/import/completion-email.ts +9 -4
  323. package/core/server/services/members/import-export/import/importer.js +25 -4
  324. package/core/server/services/members/import-export/import/importer.ts +26 -6
  325. package/core/server/services/members/import-export/import/row.ts +5 -1
  326. package/core/server/services/members/import-export/index.js +1 -5
  327. package/core/server/services/members/import-export/index.ts +2 -6
  328. package/core/server/services/members/members-api/repositories/member-repository.js +51 -0
  329. package/core/server/services/members-custom-fields/queries.js +4 -13
  330. package/core/server/services/members-custom-fields/queries.ts +4 -13
  331. package/core/server/services/members-custom-fields/schema.js +18 -27
  332. package/core/server/services/members-custom-fields/schema.ts +17 -27
  333. package/core/server/services/members-custom-fields/storage.js +94 -27
  334. package/core/server/services/members-custom-fields/storage.ts +114 -39
  335. package/core/server/services/members-custom-fields/values-service.js +98 -219
  336. package/core/server/services/members-custom-fields/values-service.ts +110 -238
  337. package/core/server/services/mentions/resource-service.js +1 -1
  338. package/core/server/services/mentions/service.js +2 -2
  339. package/core/server/services/route-settings/dynamic-routing-service.js +9 -59
  340. package/core/server/services/slack-notifications/slack-notifications.js +2 -2
  341. package/core/server/services/slack-ping/index.js +1 -1
  342. package/core/server/services/slack-ping/index.ts +1 -1
  343. package/core/server/services/slack-ping/slack-ping-service.js +3 -2
  344. package/core/server/services/slack-ping/slack-ping-service.ts +4 -5
  345. package/core/server/services/stats/content-stats-service.js +3 -3
  346. package/core/server/services/stats/members-stats-service.js +0 -7
  347. package/core/server/services/stats/posts-stats-service.js +2 -2
  348. package/core/server/services/themes/storage.js +19 -2
  349. package/core/server/services/url/config.js +90 -135
  350. package/core/server/services/url/index.js +6 -49
  351. package/core/server/services/url/lazy-find-resource.js +14 -11
  352. package/core/server/services/url/lazy-find-resource.ts +14 -11
  353. package/core/server/services/url/lazy-url-service.js +174 -94
  354. package/core/server/services/url/lazy-url-service.ts +233 -97
  355. package/core/server/services/url/routable-resources.js +62 -71
  356. package/core/server/services/url/router-filter.js +12 -4
  357. package/core/server/services/url/router-filter.ts +12 -4
  358. package/core/server/services/webhooks/index.js +1 -1
  359. package/core/server/services/webhooks/serialize.js +12 -2
  360. package/core/server/web/api/endpoints/admin/routes.js +2 -2
  361. package/core/shared/config/env/config.testing-mysql.json +1 -2
  362. package/core/shared/config/env/config.testing.json +1 -2
  363. package/core/shared/custom-theme-settings-cache/custom-theme-settings-bread-service.js +4 -0
  364. package/core/shared/custom-theme-settings-cache/custom-theme-settings-service.js +39 -0
  365. package/core/shared/events/index.js +1 -2
  366. package/core/shared/labs.js +4 -4
  367. package/package.json +10 -11
  368. package/pnpm-lock.yaml +44 -47
  369. package/pnpm-workspace.yaml +19 -19
  370. package/tsconfig.json +1 -0
  371. package/components/tryghost-adapter-base-scheduling-0.2.0.tgz +0 -0
  372. package/components/tryghost-kg-converters-1.2.3.tgz +0 -0
  373. package/components/tryghost-kg-default-cards-10.3.3.tgz +0 -0
  374. package/components/tryghost-kg-default-nodes-2.1.4.tgz +0 -0
  375. package/core/built/admin/assets/Combination-BCm9FL4o.js +0 -41
  376. package/core/built/admin/assets/activitypub/layout-CTgrezN7.js +0 -1
  377. package/core/built/admin/assets/automated-emails-6t2bIRWf.js +0 -7
  378. package/core/built/admin/assets/checkbox-BIl077a0.js +0 -1
  379. package/core/built/admin/assets/chunk.524.87b52f4fada529df2c4c.js +0 -25
  380. package/core/built/admin/assets/chunk.582.340bcca873e806cbd4bb.js +0 -27
  381. package/core/built/admin/assets/code-editor-view-C0aWNwdl.js +0 -1
  382. package/core/built/admin/assets/comments-qwhIjH3c.js +0 -1
  383. package/core/built/admin/assets/disabled-sources-indicator-DYAXW-6V.js +0 -1
  384. package/core/built/admin/assets/dist-BUKmD51u.js +0 -1
  385. package/core/built/admin/assets/dist-CNlMj7ML.js +0 -1
  386. package/core/built/admin/assets/dist-DDY6GRVz.js +0 -1
  387. package/core/built/admin/assets/dist-DG78yroX.js +0 -23
  388. package/core/built/admin/assets/editor-DDYSOXGN.js +0 -8
  389. package/core/built/admin/assets/esm-CFX93H5M.js +0 -2
  390. package/core/built/admin/assets/filters-CLehPo_D.js +0 -1
  391. package/core/built/admin/assets/index-08n05-rc.js +0 -67
  392. package/core/built/admin/assets/index-DgUzgFvS.css +0 -1
  393. package/core/built/admin/assets/label-picker-DVnpu_IF.js +0 -1
  394. package/core/built/admin/assets/layout-B0YLh7R9.js +0 -1
  395. package/core/built/admin/assets/member-custom-fields-C8NpZYza.js +0 -1
  396. package/core/built/admin/assets/member-detail-CIVAdKXf.js +0 -1
  397. package/core/built/admin/assets/members-oLPiSkXD.js +0 -10
  398. package/core/built/admin/assets/modals-CB7v-k3T.js +0 -31
  399. package/core/built/admin/assets/newsletter-rbeDX9Wk.js +0 -1
  400. package/core/built/admin/assets/overview--4V-kx9c.js +0 -1
  401. package/core/built/admin/assets/overview-DSLv30oz.js +0 -1
  402. package/core/built/admin/assets/post-analytics-header-pU2m9ZuV.js +0 -1
  403. package/core/built/admin/assets/preferences-Ru4CRPHC.js +0 -5
  404. package/core/built/admin/assets/profile-BNb1oj7D.js +0 -1
  405. package/core/built/admin/assets/select-B0HteHrp.js +0 -1
  406. package/core/built/admin/assets/settings-B1C9Q3wo.js +0 -4
  407. package/core/built/admin/assets/social-urls-DA2lXrhW.js +0 -8
  408. package/core/built/admin/assets/switch-CyQcwMAv.js +0 -1
  409. package/core/built/admin/assets/tabs-D4y1gqUd.js +0 -1
  410. package/core/built/admin/assets/tags-Dmft-Y4O.js +0 -1
  411. package/core/built/admin/assets/toggle-group-R2QMFvXW.js +0 -1
  412. package/core/built/admin/assets/use-filter-params-WrdhAISv.js +0 -1
  413. package/core/built/admin/assets/web-BqW0b0_C.js +0 -1
  414. package/core/built/admin/assets/web-Cy5GKMWM.js +0 -2
  415. package/core/server/services/email-analytics/jobs/update-member-email-analytics/index.js +0 -14
  416. package/core/server/services/url/local-file-cache.js +0 -75
  417. package/core/server/services/url/queue.js +0 -260
  418. package/core/server/services/url/resource.js +0 -102
  419. package/core/server/services/url/resources.js +0 -480
  420. package/core/server/services/url/url-generator.js +0 -276
  421. package/core/server/services/url/url-service-facade.js +0 -366
  422. package/core/server/services/url/url-service-facade.ts +0 -519
  423. package/core/server/services/url/url-service.js +0 -387
  424. package/core/server/services/url/urls.js +0 -140
  425. package/core/shared/events/url-resource-updated-event.js +0 -33
  426. /package/core/built/admin/assets/{chunk.211.6f7328d63c41536451b3.js.LICENSE.txt → chunk.571.40f093ed6d883993714e.js.LICENSE.txt} +0 -0
  427. /package/core/built/admin/assets/{dist-CqO2lWS0.js → dist-CqO2lWS02.js} +0 -0
  428. /package/core/server/api/endpoints/{gift-reminders.js → gifts.js} +0 -0
@@ -96,11 +96,13 @@ module.exports = function (Bookshelf) {
96
96
  (value, key) => key.startsWith(PIVOT_PREFIX)
97
97
  );
98
98
 
99
- if (this.relationships) {
100
- this.relationships.forEach((relation) => {
101
- if (this._previousRelations && Object.prototype.hasOwnProperty.call(this._previousRelations, relation)) {
102
- clonedModel.related(relation).models = this._previousRelations[relation].models;
103
- }
99
+ // Iterate `_previousRelations` rather than `relationships` — a relation
100
+ // can carry previous state without being managed by bookshelf-relations
101
+ // (e.g. a member's stripeSubscriptions). Behaviour is unchanged for
102
+ // relations that are in both.
103
+ if (this._previousRelations) {
104
+ Object.keys(this._previousRelations).forEach((relation) => {
105
+ clonedModel.related(relation).models = this._previousRelations[relation].models;
104
106
  });
105
107
  }
106
108
 
@@ -1006,8 +1006,8 @@ Post = ghostBookshelf.Model.extend({
1006
1006
  * - `slug`: /:slug/
1007
1007
  * - `published_at`: /:year/:slug
1008
1008
  * - `author_id`: /:author/:slug, /:primary_author/:slug
1009
- * - now, the UrlService pre-generates urls based on the resources
1010
- * - you can ask `urlService.getUrlByResourceId(post.id)`
1009
+ * - now, the UrlService computes urls from the routing config
1010
+ * - you can ask `urlService.getUrlForResource(post)`
1011
1011
  *
1012
1012
  * ### events
1013
1013
  * - you call `findAll` with `columns: id`
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AdapterManager = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
7
  const errors_1 = __importDefault(require("@tryghost/errors"));
9
8
  const utils_1 = require("./utils");
10
9
  /**
@@ -121,50 +120,7 @@ class AdapterManager {
121
120
  message: `Unable to find ${adapterType} adapter in ${this.pathsToAdapters}.`
122
121
  });
123
122
  }
124
- let Adapter = null;
125
- for (const pathToAdapters of this.pathsToAdapters) {
126
- let pathToAdapter = node_path_1.default.join(pathToAdapters, adapterType, adapterClassName);
127
- if (pathToAdapters === '') {
128
- // We are loading from node_modules, we can remove the `adapterType` prefix
129
- pathToAdapter = node_path_1.default.join(pathToAdapters, adapterClassName);
130
- }
131
- // An adapter directory may be a full module with its own
132
- // package.json, in which case this resolves the `exports` entry
133
- // point; otherwise the path passes through unchanged.
134
- const moduleToLoad = (0, utils_1.resolveAdapterEntryPoint)(pathToAdapter);
135
- try {
136
- const adapterModule = this.loadAdapterFromPath(moduleToLoad);
137
- Adapter = (0, utils_1.resolveAdapterExport)(adapterModule);
138
- if (Adapter) {
139
- break;
140
- }
141
- }
142
- catch (err) {
143
- // Catch runtime errors
144
- if (!(err instanceof Error) || err.code !== 'MODULE_NOT_FOUND') {
145
- throw new errors_1.default.IncorrectUsageError({ err: err });
146
- }
147
- // Catch missing dependencies BUT NOT missing adapter.
148
- // Only check the first line — Node appends a "Require stack"
149
- // that includes the adapter's own path, which would false-positive.
150
- const firstLine = err.message.split('\n')[0];
151
- if (!firstLine.includes(pathToAdapter)) {
152
- // Name the unresolved module so the error is actionable, e.g.
153
- // "Cannot find module 'superagent'" -> 'superagent'.
154
- const missingMatch = /Cannot find module '([^']+)'/.exec(firstLine);
155
- const missingModule = missingMatch ? ` '${missingMatch[1]}'` : '';
156
- throw new errors_1.default.IncorrectUsageError({
157
- message: `You are missing a dependency${missingModule} in your adapter ${pathToAdapter}`,
158
- err: err
159
- });
160
- }
161
- }
162
- }
163
- if (!Adapter) {
164
- throw new errors_1.default.IncorrectUsageError({
165
- message: `Unable to find ${adapterType} adapter ${adapterClassName} in ${this.pathsToAdapters}.`
166
- });
167
- }
123
+ const Adapter = (0, utils_1.loadAdapterClass)(adapterType, adapterClassName, this.pathsToAdapters, this.loadAdapterFromPath);
168
124
  return { Adapter, adapterConfig: adapterConfig ?? {}, adapterType, adapterClassName };
169
125
  }
170
126
  /**
@@ -1,6 +1,5 @@
1
- import path from 'node:path';
2
1
  import errors from '@tryghost/errors';
3
- import {resolveAdapterExport, resolveAdapterEntryPoint, resolveAdapterOptions, normalizeAdapterConfig, getConfiguredFeatures} from './utils';
2
+ import {loadAdapterClass, resolveAdapterOptions, normalizeAdapterConfig, getConfiguredFeatures} from './utils';
4
3
  import type {ConfigInstance} from '../../../shared/config/loader';
5
4
  import type {
6
5
  Adapter,
@@ -186,52 +185,7 @@ export class AdapterManager<BaseClasses extends BaseClassMap = BaseClassMap> {
186
185
  });
187
186
  }
188
187
 
189
- let Adapter: AdapterConstructor | null = null;
190
- for (const pathToAdapters of this.pathsToAdapters) {
191
- let pathToAdapter = path.join(pathToAdapters, adapterType, adapterClassName);
192
- if (pathToAdapters === '') {
193
- // We are loading from node_modules, we can remove the `adapterType` prefix
194
- pathToAdapter = path.join(pathToAdapters, adapterClassName);
195
- }
196
- // An adapter directory may be a full module with its own
197
- // package.json, in which case this resolves the `exports` entry
198
- // point; otherwise the path passes through unchanged.
199
- const moduleToLoad = resolveAdapterEntryPoint(pathToAdapter);
200
-
201
- try {
202
- const adapterModule = this.loadAdapterFromPath(moduleToLoad);
203
- Adapter = resolveAdapterExport(adapterModule);
204
- if (Adapter) {
205
- break;
206
- }
207
- } catch (err) {
208
- // Catch runtime errors
209
- if (!(err instanceof Error) || (err as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') {
210
- throw new errors.IncorrectUsageError({err: err as Error});
211
- }
212
-
213
- // Catch missing dependencies BUT NOT missing adapter.
214
- // Only check the first line — Node appends a "Require stack"
215
- // that includes the adapter's own path, which would false-positive.
216
- const firstLine = err.message.split('\n')[0];
217
- if (!firstLine.includes(pathToAdapter)) {
218
- // Name the unresolved module so the error is actionable, e.g.
219
- // "Cannot find module 'superagent'" -> 'superagent'.
220
- const missingMatch = /Cannot find module '([^']+)'/.exec(firstLine);
221
- const missingModule = missingMatch ? ` '${missingMatch[1]}'` : '';
222
- throw new errors.IncorrectUsageError({
223
- message: `You are missing a dependency${missingModule} in your adapter ${pathToAdapter}`,
224
- err: err as Error
225
- });
226
- }
227
- }
228
- }
229
-
230
- if (!Adapter) {
231
- throw new errors.IncorrectUsageError({
232
- message: `Unable to find ${adapterType} adapter ${adapterClassName} in ${this.pathsToAdapters}.`
233
- });
234
- }
188
+ const Adapter = loadAdapterClass(adapterType, adapterClassName, this.pathsToAdapters, this.loadAdapterFromPath);
235
189
 
236
190
  return {Adapter, adapterConfig: adapterConfig ?? {}, adapterType, adapterClassName};
237
191
  }
@@ -0,0 +1,28 @@
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.adapterPaths = void 0;
7
+ exports.buildAdapterPaths = buildAdapterPaths;
8
+ const config_1 = __importDefault(require("../../../shared/config"));
9
+ /**
10
+ * Where adapters are looked up, in order. Also read by bin/validate-adapters.ts,
11
+ * which checks adapter implementations at build time - keep this the only place
12
+ * the lookup order is declared, so a name resolves there exactly as it does here.
13
+ */
14
+ function buildAdapterPaths(configInstance) {
15
+ return Array.from(new Set([
16
+ '', // A blank path will cause us to check node_modules for the adapter
17
+ configInstance.get('paths').internalAdaptersPath,
18
+ // custom docker builds may install adapters in a separate path from content,
19
+ // since the content dir is often bind-mounted into the container. Offering
20
+ // an escape hatch here to allow for this
21
+ configInstance.get('paths').installedAdaptersPath ?? '',
22
+ // load adapters from content last, so that they don't override any other
23
+ // internal or platform-installed adapters
24
+ // TODO: potentially deprecate/remove as part of Ghost 7.0
25
+ configInstance.getContentPath('adapters')
26
+ ]));
27
+ }
28
+ exports.adapterPaths = buildAdapterPaths(config_1.default);
@@ -0,0 +1,26 @@
1
+ import config from '../../../shared/config';
2
+ import type {ConfigInstance} from '../../../shared/config/loader';
3
+
4
+ /**
5
+ * Where adapters are looked up, in order. Also read by bin/validate-adapters.ts,
6
+ * which checks adapter implementations at build time - keep this the only place
7
+ * the lookup order is declared, so a name resolves there exactly as it does here.
8
+ */
9
+ export function buildAdapterPaths(configInstance: ConfigInstance): string[] {
10
+ return Array.from(new Set<string>([
11
+ '', // A blank path will cause us to check node_modules for the adapter
12
+ configInstance.get('paths').internalAdaptersPath,
13
+
14
+ // custom docker builds may install adapters in a separate path from content,
15
+ // since the content dir is often bind-mounted into the container. Offering
16
+ // an escape hatch here to allow for this
17
+ configInstance.get('paths').installedAdaptersPath ?? '',
18
+
19
+ // load adapters from content last, so that they don't override any other
20
+ // internal or platform-installed adapters
21
+ // TODO: potentially deprecate/remove as part of Ghost 7.0
22
+ configInstance.getContentPath('adapters')
23
+ ]));
24
+ }
25
+
26
+ export const adapterPaths: string[] = buildAdapterPaths(config);
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.baseClasses = void 0;
4
+ const ghost_storage_base_1 = require("ghost-storage-base");
5
+ const adapter_base_scheduling_1 = require("@tryghost/adapter-base-scheduling");
6
+ const adapter_base_sso_1 = require("@tryghost/adapter-base-sso");
7
+ const adapter_base_cache_1 = require("@tryghost/adapter-base-cache");
8
+ const adapter_base_redirects_1 = require("@tryghost/adapter-base-redirects");
9
+ const adapter_base_route_settings_1 = require("@tryghost/adapter-base-route-settings");
10
+ /**
11
+ * The base class every adapter of a given type must extend. Also read by
12
+ * bin/validate-adapters.js, which checks adapter implementations at build time -
13
+ * keep this the only place the mapping is declared.
14
+ */
15
+ exports.baseClasses = {
16
+ storage: ghost_storage_base_1.StorageBase,
17
+ scheduling: adapter_base_scheduling_1.SchedulingBase,
18
+ sso: adapter_base_sso_1.SSOBase,
19
+ cache: adapter_base_cache_1.CacheBase,
20
+ redirects: adapter_base_redirects_1.RedirectsStoreBase,
21
+ 'route-settings': adapter_base_route_settings_1.RouteSettingsStoreBase
22
+ };
@@ -0,0 +1,22 @@
1
+ import {StorageBase} from 'ghost-storage-base';
2
+ import {SchedulingBase} from '@tryghost/adapter-base-scheduling';
3
+ import {SSOBase} from '@tryghost/adapter-base-sso';
4
+ import {CacheBase} from '@tryghost/adapter-base-cache';
5
+ import {RedirectsStoreBase} from '@tryghost/adapter-base-redirects';
6
+ import {RouteSettingsStoreBase} from '@tryghost/adapter-base-route-settings';
7
+
8
+ import type {BaseClassMap} from './adapter-manager';
9
+
10
+ /**
11
+ * The base class every adapter of a given type must extend. Also read by
12
+ * bin/validate-adapters.js, which checks adapter implementations at build time -
13
+ * keep this the only place the mapping is declared.
14
+ */
15
+ export const baseClasses = {
16
+ storage: StorageBase,
17
+ scheduling: SchedulingBase,
18
+ sso: SSOBase,
19
+ cache: CacheBase,
20
+ redirects: RedirectsStoreBase,
21
+ 'route-settings': RouteSettingsStoreBase
22
+ } satisfies BaseClassMap;
@@ -3,40 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const ghost_storage_base_1 = require("ghost-storage-base");
7
- const adapter_base_scheduling_1 = require("@tryghost/adapter-base-scheduling");
8
- const adapter_base_sso_1 = require("@tryghost/adapter-base-sso");
9
- const adapter_base_cache_1 = require("@tryghost/adapter-base-cache");
10
- const adapter_base_redirects_1 = require("@tryghost/adapter-base-redirects");
11
- const adapter_base_route_settings_1 = require("@tryghost/adapter-base-route-settings");
12
6
  const adapter_manager_1 = require("./adapter-manager");
7
+ const adapter_paths_1 = require("./adapter-paths");
8
+ const base_classes_1 = require("./base-classes");
13
9
  const config_1 = __importDefault(require("../../../shared/config"));
14
- const adapterPaths = new Set([
15
- '', // A blank path will cause us to check node_modules for the adapter
16
- config_1.default.get('paths').internalAdaptersPath,
17
- // custom docker builds may install adapters in a separate path from content,
18
- // since the content dir is often bind-mounted into the container. Offering
19
- // an escape hatch here to allow for this
20
- config_1.default.get('paths').installedAdaptersPath ?? '',
21
- // load adapters from content last, so that they don't override any other
22
- // internal or platform-installed adapters
23
- // TODO: potentially deprecate/remove as part of Ghost 7.0
24
- config_1.default.getContentPath('adapters'),
25
- ]);
26
10
  // A singleton adapter manager, preconfigured with the base classes for every
27
11
  // known adapter type. `getAdapter` resolves the active adapter and its options
28
12
  // from config on each call, so runtime config changes are always reflected.
29
13
  const adapterManager = new adapter_manager_1.AdapterManager({
30
14
  loadAdapterFromPath: require,
31
15
  config: config_1.default,
32
- pathsToAdapters: Array.from(adapterPaths),
33
- baseClasses: {
34
- storage: ghost_storage_base_1.StorageBase,
35
- scheduling: adapter_base_scheduling_1.SchedulingBase,
36
- sso: adapter_base_sso_1.SSOBase,
37
- cache: adapter_base_cache_1.CacheBase,
38
- redirects: adapter_base_redirects_1.RedirectsStoreBase,
39
- 'route-settings': adapter_base_route_settings_1.RouteSettingsStoreBase
40
- }
16
+ pathsToAdapters: adapter_paths_1.adapterPaths,
17
+ baseClasses: base_classes_1.baseClasses
41
18
  });
42
19
  exports.default = adapterManager;
@@ -1,43 +1,16 @@
1
- import {StorageBase} from 'ghost-storage-base';
2
- import {SchedulingBase} from '@tryghost/adapter-base-scheduling';
3
- import {SSOBase} from '@tryghost/adapter-base-sso';
4
- import {CacheBase} from '@tryghost/adapter-base-cache';
5
- import {RedirectsStoreBase} from '@tryghost/adapter-base-redirects';
6
- import {RouteSettingsStoreBase} from '@tryghost/adapter-base-route-settings';
7
-
8
1
  import {AdapterManager} from './adapter-manager';
2
+ import {adapterPaths} from './adapter-paths';
3
+ import {baseClasses} from './base-classes';
9
4
  import config from '../../../shared/config';
10
5
 
11
- const adapterPaths = new Set<string>([
12
- '', // A blank path will cause us to check node_modules for the adapter
13
- config.get('paths').internalAdaptersPath,
14
-
15
- // custom docker builds may install adapters in a separate path from content,
16
- // since the content dir is often bind-mounted into the container. Offering
17
- // an escape hatch here to allow for this
18
- config.get('paths').installedAdaptersPath ?? '',
19
-
20
- // load adapters from content last, so that they don't override any other
21
- // internal or platform-installed adapters
22
- // TODO: potentially deprecate/remove as part of Ghost 7.0
23
- config.getContentPath('adapters'),
24
- ]);
25
-
26
6
  // A singleton adapter manager, preconfigured with the base classes for every
27
7
  // known adapter type. `getAdapter` resolves the active adapter and its options
28
8
  // from config on each call, so runtime config changes are always reflected.
29
9
  const adapterManager = new AdapterManager({
30
10
  loadAdapterFromPath: require,
31
11
  config,
32
- pathsToAdapters: Array.from(adapterPaths),
33
- baseClasses: {
34
- storage: StorageBase,
35
- scheduling: SchedulingBase,
36
- sso: SSOBase,
37
- cache: CacheBase,
38
- redirects: RedirectsStoreBase,
39
- 'route-settings': RouteSettingsStoreBase
40
- }
12
+ pathsToAdapters: adapterPaths,
13
+ baseClasses
41
14
  });
42
15
 
43
16
  export default adapterManager;
@@ -5,12 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolveAdapterEntryPoint = resolveAdapterEntryPoint;
7
7
  exports.resolveAdapterExport = resolveAdapterExport;
8
+ exports.loadAdapterClass = loadAdapterClass;
8
9
  exports.normalizeAdapterConfig = normalizeAdapterConfig;
9
10
  exports.getConfiguredFeatures = getConfiguredFeatures;
10
11
  exports.resolveAdapterOptions = resolveAdapterOptions;
11
12
  const node_fs_1 = __importDefault(require("node:fs"));
12
13
  const node_path_1 = __importDefault(require("node:path"));
13
14
  const node_module_1 = require("node:module");
15
+ const errors_1 = __importDefault(require("@tryghost/errors"));
14
16
  /**
15
17
  * Whether `filePath` resolves to a location inside `directory`.
16
18
  *
@@ -116,6 +118,54 @@ function resolveAdapterExport(moduleExport) {
116
118
  }
117
119
  return null;
118
120
  }
121
+ /**
122
+ * Locate and load an adapter constructor by type and class name, trying each of
123
+ * `pathsToAdapters` in order. Shared by the adapter manager and by
124
+ * bin/validate-adapters.ts, so a name resolves — and fails — identically at build
125
+ * time and at runtime.
126
+ */
127
+ function loadAdapterClass(adapterType, adapterClassName, pathsToAdapters, loadAdapterFromPath) {
128
+ for (const pathToAdapters of pathsToAdapters) {
129
+ let pathToAdapter = node_path_1.default.join(pathToAdapters, adapterType, adapterClassName);
130
+ if (pathToAdapters === '') {
131
+ // We are loading from node_modules, we can remove the `adapterType` prefix
132
+ pathToAdapter = node_path_1.default.join(pathToAdapters, adapterClassName);
133
+ }
134
+ // An adapter directory may be a full module with its own
135
+ // package.json, in which case this resolves the `exports` entry
136
+ // point; otherwise the path passes through unchanged.
137
+ const moduleToLoad = resolveAdapterEntryPoint(pathToAdapter);
138
+ try {
139
+ const Adapter = resolveAdapterExport(loadAdapterFromPath(moduleToLoad));
140
+ if (Adapter) {
141
+ return Adapter;
142
+ }
143
+ }
144
+ catch (err) {
145
+ // Catch runtime errors
146
+ if (!(err instanceof Error) || err.code !== 'MODULE_NOT_FOUND') {
147
+ throw new errors_1.default.IncorrectUsageError({ err: err });
148
+ }
149
+ // Catch missing dependencies BUT NOT missing adapter.
150
+ // Only check the first line — Node appends a "Require stack"
151
+ // that includes the adapter's own path, which would false-positive.
152
+ const firstLine = err.message.split('\n')[0];
153
+ if (!firstLine.includes(pathToAdapter)) {
154
+ // Name the unresolved module so the error is actionable, e.g.
155
+ // "Cannot find module 'superagent'" -> 'superagent'.
156
+ const missingMatch = /Cannot find module '([^']+)'/.exec(firstLine);
157
+ const missingModule = missingMatch ? ` '${missingMatch[1]}'` : '';
158
+ throw new errors_1.default.IncorrectUsageError({
159
+ message: `You are missing a dependency${missingModule} in your adapter ${pathToAdapter}`,
160
+ err: err
161
+ });
162
+ }
163
+ }
164
+ }
165
+ throw new errors_1.default.IncorrectUsageError({
166
+ message: `Unable to find ${adapterType} adapter ${adapterClassName} in ${pathsToAdapters}.`
167
+ });
168
+ }
119
169
  function getSchedulingConfig(config) {
120
170
  const adapterConfig = config.get('adapters:scheduling');
121
171
  if (!adapterConfig) {
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import {createRequire} from 'node:module';
4
+ import errors from '@tryghost/errors';
4
5
  import type {AdapterConstructor} from "./types";
5
6
  import type {ConfigInstance} from '../../../shared/config/loader';
6
7
 
@@ -122,6 +123,62 @@ export function resolveAdapterExport(moduleExport: unknown): AdapterConstructor
122
123
  return null;
123
124
  }
124
125
 
126
+ /**
127
+ * Locate and load an adapter constructor by type and class name, trying each of
128
+ * `pathsToAdapters` in order. Shared by the adapter manager and by
129
+ * bin/validate-adapters.ts, so a name resolves — and fails — identically at build
130
+ * time and at runtime.
131
+ */
132
+ export function loadAdapterClass(
133
+ adapterType: string,
134
+ adapterClassName: string,
135
+ pathsToAdapters: string[],
136
+ loadAdapterFromPath: (path: string) => unknown
137
+ ): AdapterConstructor {
138
+ for (const pathToAdapters of pathsToAdapters) {
139
+ let pathToAdapter = path.join(pathToAdapters, adapterType, adapterClassName);
140
+ if (pathToAdapters === '') {
141
+ // We are loading from node_modules, we can remove the `adapterType` prefix
142
+ pathToAdapter = path.join(pathToAdapters, adapterClassName);
143
+ }
144
+ // An adapter directory may be a full module with its own
145
+ // package.json, in which case this resolves the `exports` entry
146
+ // point; otherwise the path passes through unchanged.
147
+ const moduleToLoad = resolveAdapterEntryPoint(pathToAdapter);
148
+
149
+ try {
150
+ const Adapter = resolveAdapterExport(loadAdapterFromPath(moduleToLoad));
151
+ if (Adapter) {
152
+ return Adapter;
153
+ }
154
+ } catch (err) {
155
+ // Catch runtime errors
156
+ if (!(err instanceof Error) || (err as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') {
157
+ throw new errors.IncorrectUsageError({err: err as Error});
158
+ }
159
+
160
+ // Catch missing dependencies BUT NOT missing adapter.
161
+ // Only check the first line — Node appends a "Require stack"
162
+ // that includes the adapter's own path, which would false-positive.
163
+ const firstLine = err.message.split('\n')[0];
164
+ if (!firstLine.includes(pathToAdapter)) {
165
+ // Name the unresolved module so the error is actionable, e.g.
166
+ // "Cannot find module 'superagent'" -> 'superagent'.
167
+ const missingMatch = /Cannot find module '([^']+)'/.exec(firstLine);
168
+ const missingModule = missingMatch ? ` '${missingMatch[1]}'` : '';
169
+ throw new errors.IncorrectUsageError({
170
+ message: `You are missing a dependency${missingModule} in your adapter ${pathToAdapter}`,
171
+ err: err as Error
172
+ });
173
+ }
174
+ }
175
+ }
176
+
177
+ throw new errors.IncorrectUsageError({
178
+ message: `Unable to find ${adapterType} adapter ${adapterClassName} in ${pathsToAdapters}.`
179
+ });
180
+ }
181
+
125
182
  function getSchedulingConfig(config: ConfigInstance) {
126
183
  const adapterConfig = config.get('adapters:scheduling');
127
184
  if (!adapterConfig) {
@@ -1,5 +1,6 @@
1
1
  const Feedback = require('./feedback');
2
2
  const errors = require('@tryghost/errors');
3
+ const permissions = require('../../services/permissions');
3
4
  const tpl = require('@tryghost/tpl');
4
5
 
5
6
  const messages = {
@@ -50,7 +51,7 @@ class AudienceFeedbackController {
50
51
  // Load the full post (with tags/authors) rather than passing an
51
52
  // id-only resource: the URL service needs status to apply the
52
53
  // published base filter and tags/authors to evaluate filtered
53
- // routes — the lazy backend rejects a bare {id} as thin.
54
+ // routes — the URL service reports a bare {id} as thin.
54
55
  const post = await this.#repository.getPostById(postId, {withRelated: ['tags', 'authors']});
55
56
  const target = post
56
57
  ? this.#audienceFeedbackService.buildLink(uuid, post, score, key)
@@ -118,7 +119,8 @@ class AudienceFeedbackController {
118
119
  const postId = frame.data.id;
119
120
  const options = {
120
121
  limit: frame.options.limit || 10,
121
- page: frame.options.page || 1
122
+ page: frame.options.page || 1,
123
+ withMember: false
122
124
  };
123
125
 
124
126
  // Add score filter if specified
@@ -126,6 +128,13 @@ class AudienceFeedbackController {
126
128
  options.score = parseInt(frame.options.score);
127
129
  }
128
130
 
131
+ try {
132
+ await permissions.canThis(frame.options.context).browse.member();
133
+ options.withMember = true;
134
+ } catch {
135
+ // permissions throws; we want to return data but without member info
136
+ }
137
+
129
138
  const result = await this.#repository.getForPost(postId, options);
130
139
  return result;
131
140
  }
@@ -24,7 +24,7 @@ class AudienceFeedbackService {
24
24
  */
25
25
  buildLink(uuid, post, score, key) {
26
26
  const postData = toPlain(post);
27
- let postUrl = this.#urlService.facade.getUrlForResource({...postData, type: 'posts'}, {absolute: true});
27
+ let postUrl = this.#urlService.getUrlForResource({...postData, type: 'posts'}, {absolute: true});
28
28
 
29
29
  if (postUrl.match(/\/404\//)) {
30
30
  postUrl = this.#baseURL;
@@ -36,7 +36,7 @@ class AudienceFeedbackService {
36
36
  * Feedback link for a post that no longer exists. Goes straight to the
37
37
  * home page — the same destination buildLink picks when the URL service
38
38
  * has no URL for the post — without asking the URL service: an id-only
39
- * resource can't be routed (the lazy backend rejects it as thin).
39
+ * resource can't be routed (the URL service reports it as thin).
40
40
  *
41
41
  * @param {string} uuid
42
42
  * @param {string} postId
@@ -76,10 +76,13 @@ module.exports = class FeedbackRepository {
76
76
  limit: options.limit || 10,
77
77
  page: options.page || 1,
78
78
  order: 'created_at DESC',
79
- withRelated: ['member'],
80
79
  filter: filter
81
80
  };
82
81
 
82
+ if (options.withMember) {
83
+ findOptions.withRelated = ['member'];
84
+ }
85
+
83
86
  // Use findPage with filter
84
87
  const results = await this.#MemberFeedback.findPage(findOptions);
85
88
 
@@ -26,6 +26,7 @@ const AUTH_CODE_CHALLENGE_BYTES = 16;
26
26
  * @prop {string} user_agent
27
27
  * @prop {string} ip
28
28
  * @prop {boolean} verified
29
+ * @prop {string} [verified_user_id]
29
30
  * @prop {string} [auth_code_challenge]
30
31
  * @prop {number} [auth_code_generated_at]
31
32
  */
@@ -190,12 +191,14 @@ module.exports = function createSessionService({
190
191
 
191
192
  if (isAuthCodeVerified) {
192
193
  session.verified = true;
194
+ session.verified_user_id = user.id;
193
195
  invalidateAuthCodeChallenge(session);
194
196
  }
195
197
  }
196
198
 
197
199
  if (isStaffDeviceVerificationDisabled()) {
198
200
  session.verified = true;
201
+ session.verified_user_id = user.id;
199
202
  }
200
203
  }
201
204
 
@@ -214,6 +217,7 @@ module.exports = function createSessionService({
214
217
  const {
215
218
  user_id: previousUserId,
216
219
  verified: previousVerified,
220
+ verified_user_id: previousVerifiedUserId,
217
221
  auth_code_challenge: previousAuthCodeChallenge,
218
222
  auth_code_generated_at: previousAuthCodeGeneratedAt
219
223
  } = previousSession;
@@ -231,8 +235,11 @@ module.exports = function createSessionService({
231
235
 
232
236
  const session = req.session;
233
237
  session.user_id = previousUserId;
234
- // A different user doesn't inherit the previous user's verification
235
- session.verified = previousUserId && previousUserId !== user.id ? undefined : previousVerified;
238
+ // Verification is bound to the user who completed it any other user
239
+ // (including sessions with no verified_user_id) must verify again
240
+ const carryVerification = previousVerified === true && previousVerifiedUserId === user.id;
241
+ session.verified = carryVerification ? true : undefined;
242
+ session.verified_user_id = carryVerification ? previousVerifiedUserId : undefined;
236
243
  session.auth_code_challenge = previousAuthCodeChallenge;
237
244
  session.auth_code_generated_at = previousAuthCodeGeneratedAt;
238
245
 
@@ -282,6 +289,7 @@ module.exports = function createSessionService({
282
289
  });
283
290
 
284
291
  session.verified = true;
292
+ session.verified_user_id = user.id;
285
293
  invalidateAuthCodeChallenge(session);
286
294
  }
287
295
 
@@ -480,6 +488,7 @@ module.exports = function createSessionService({
480
488
  async function verifySession(req, res) {
481
489
  const session = await getSession(req, res);
482
490
  session.verified = true;
491
+ session.verified_user_id = session.user_id;
483
492
  invalidateAuthCodeChallenge(session);
484
493
  }
485
494
 
@@ -491,7 +500,12 @@ module.exports = function createSessionService({
491
500
  */
492
501
  async function isVerifiedSession(req, res) {
493
502
  const session = await getSession(req, res);
494
- return session.verified;
503
+ // Verification is bound to a user; a session with no verified_user_id
504
+ // (e.g. logged out, or predating this field) fails closed rather than
505
+ // matching an absent user_id via undefined === undefined
506
+ return session.verified === true &&
507
+ !!session.verified_user_id &&
508
+ session.verified_user_id === session.user_id;
495
509
  }
496
510
 
497
511
  /**
@@ -506,6 +520,7 @@ module.exports = function createSessionService({
506
520
 
507
521
  if (isVerificationRequired()) {
508
522
  session.verified = undefined;
523
+ session.verified_user_id = undefined;
509
524
  }
510
525
 
511
526
  invalidateAuthCodeChallenge(session);