ghost 6.53.0 → 6.54.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 (639) hide show
  1. package/components/ghost-storage-base-3.0.0.tgz +0 -0
  2. package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
  3. package/components/tryghost-adapter-base-scheduling-0.2.0.tgz +0 -0
  4. package/components/tryghost-adapter-base-sso-0.1.1.tgz +0 -0
  5. package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
  6. package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
  7. package/components/tryghost-i18n-0.0.0.tgz +0 -0
  8. package/components/tryghost-kg-converters-1.2.3.tgz +0 -0
  9. package/components/tryghost-kg-default-nodes-2.1.3.tgz +0 -0
  10. package/components/tryghost-kg-lexical-html-renderer-1.4.3.tgz +0 -0
  11. package/core/boot.js +9 -6
  12. package/core/built/admin/assets/Combination-CJG7Flp-.js +41 -0
  13. package/core/built/admin/assets/Growth-BTP1LthE.js +3 -0
  14. package/core/built/admin/assets/Newsletters-CSEX0myc.js +1 -0
  15. package/core/built/admin/assets/Overview-BjACEsJF.js +1 -0
  16. package/core/built/admin/assets/{PolarAngleAxis-pciQ0MOy.js → PolarAngleAxis-BGjf7sBu.js} +1 -1
  17. package/core/built/admin/assets/{RadialBarChart-DWmw2PcX.js → RadialBarChart-zeFf9mBz.js} +1 -1
  18. package/core/built/admin/assets/Web-CxxxjCcv.js +2 -0
  19. package/core/built/admin/assets/account-migration-BklF2I_I.js +1 -0
  20. package/core/built/admin/assets/activitypub/{account-migration-BPZG37DJ.js → account-migration-CNovr6W-.js} +13 -13
  21. package/core/built/admin/assets/activitypub/activitypub.js +8 -8
  22. package/core/built/admin/assets/activitypub/{avatar-ZYco0ITb.js → avatar-B3DEDB1l.js} +10 -10
  23. package/core/built/admin/assets/activitypub/{avatar-flipboard-D541lc4F.js → avatar-flipboard-Cqrg0XMx.js} +3 -3
  24. package/core/built/admin/assets/activitypub/{bluesky-sharing-NOHUtHjl.js → bluesky-sharing-Ceslb1_M.js} +38 -37
  25. package/core/built/admin/assets/activitypub/{chunk-KS7C4IRE-B-GOFDPZ.js → chunk-KS7C4IRE-D4HEcEwi.js} +716 -710
  26. package/core/built/admin/assets/activitypub/{content-formatters-bwrp4iEO.js → content-formatters-BpQARh28.js} +229 -181
  27. package/core/built/admin/assets/activitypub/{copy-C7m7ovHw.js → copy-D9UWIAan.js} +2 -2
  28. package/core/built/admin/assets/activitypub/{dist-BqkDUQxJ2.js → dist-ByFmDSNP2.js} +64 -63
  29. package/core/built/admin/assets/activitypub/{dist-B5ira32t.js → dist-DHAjBcV3.js} +5 -5
  30. package/core/built/admin/assets/activitypub/{domain-iqE4YXwD.js → domain-C1qQvJ8C.js} +33 -33
  31. package/core/built/admin/assets/activitypub/{edit-profile-B8MFYh28.js → edit-profile-BcH-jEfM.js} +46 -45
  32. package/core/built/admin/assets/activitypub/{explore-BbdKodp3.js → explore-AxwBh9dI.js} +20 -20
  33. package/core/built/admin/assets/activitypub/{feed-Cl3A5owG.js → feed-BaOlbh7a.js} +15 -15
  34. package/core/built/admin/assets/activitypub/{field-DL6WyR-c.js → field-B7mYYQpN.js} +13 -13
  35. package/core/built/admin/assets/activitypub/{hash-6G3DzwL9.js → hash-BC9Q0N4c.js} +2 -2
  36. package/core/built/admin/assets/activitypub/{inbox-YmhuBice.js → inbox-DQ4ZnC1m.js} +2 -2
  37. package/core/built/admin/assets/activitypub/inbox-vXez-5uJ.js +1221 -0
  38. package/core/built/admin/assets/activitypub/{label-DGbLjDvE.js → label-Chv5T8bw.js} +6 -6
  39. package/core/built/admin/assets/activitypub/layout-CziktJXo.js +1 -0
  40. package/core/built/admin/assets/activitypub/{moderation-qnBtk1zS.js → moderation-DtSM2i1I.js} +32 -31
  41. package/core/built/admin/assets/activitypub/{note-C7ZRoSJv.js → note-Dckp4S-2.js} +21 -21
  42. package/core/built/admin/assets/activitypub/{notifications-DiEA4b1o.js → notifications-CG5T22vg.js} +17 -17
  43. package/core/built/admin/assets/activitypub/{onboarding-_JVgEwgV.js → onboarding-BFDkzeR2.js} +2 -2
  44. package/core/built/admin/assets/activitypub/{onboarding-DG4zu3qM.js → onboarding-D6rcBdPe.js} +5 -5
  45. package/core/built/admin/assets/activitypub/{preferences-B3FtocnP.js → preferences-D_799jdl.js} +1607 -1606
  46. package/core/built/admin/assets/activitypub/{profile-D8ZJfYXB.js → profile-D2JfXBQl.js} +264 -263
  47. package/core/built/admin/assets/activitypub/{reply-C1vggenw.js → reply-CpdMeAO5.js} +2 -2
  48. package/core/built/admin/assets/activitypub/{routes-BOii-V9n.js → routes-CCHe2dQp.js} +1317 -1298
  49. package/core/built/admin/assets/activitypub/{separator-1gNokN5S.js → separator-BI1FLsYM.js} +4 -4
  50. package/core/built/admin/assets/activitypub/{settings--9Sb0nbl.js → settings-kx-9Enkz.js} +14 -14
  51. package/core/built/admin/assets/activitypub/{site-fkMmqv0V.js → site-x4_IjVJ0.js} +10 -10
  52. package/core/built/admin/assets/activitypub/{step-1-QhivSMw2.js → step-1-DIDg4aHb.js} +15 -15
  53. package/core/built/admin/assets/activitypub/{step-2-pMk9YwqD.js → step-2-BfGe8BYt.js} +7 -7
  54. package/core/built/admin/assets/activitypub/{step-3-DvmVC1fo.js → step-3-mE9spAqw.js} +12 -12
  55. package/core/built/admin/assets/activitypub/{tabs-Dc0FEEYD.js → tabs-CyPRQQ1N.js} +241 -237
  56. package/core/built/admin/assets/activitypub/{topic-filter-CuDyM5bD.js → topic-filter-DLHBZT93.js} +4 -4
  57. package/core/built/admin/assets/activitypub/use-activity-pub-queries-VzbN99u_.js +1957 -0
  58. package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-Drx1kdAK.js → use-navigate-with-base-path-CAwXTmqH.js} +165 -175
  59. package/core/built/admin/assets/activitypub/{use-reply-chain-data-BHkCHcW5.js → use-reply-chain-data-BAB6fNGt.js} +8 -8
  60. package/core/built/admin/assets/activitypub/users-BLeiOTHc.js +1464 -0
  61. package/core/built/admin/assets/activitypub/{x-BHCEe-c2.js → x-C8tAnXly.js} +2 -2
  62. package/core/built/admin/assets/{audience-adiFehTD.js → audience-X_XsZivI.js} +1 -1
  63. package/core/built/admin/assets/{automated-emails-UWM02CMr.js → automated-emails-of1MvVsv.js} +1 -1
  64. package/core/built/admin/assets/automations-B7-y3dXt.js +1 -0
  65. package/core/built/admin/assets/automations-DRFjW5fw.js +1 -0
  66. package/core/built/admin/assets/{avatar-flipboard-Lz3F9fNT.js → avatar-flipboard-C6Kj3Awu.js} +1 -1
  67. package/core/built/admin/assets/bluesky-sharing-BbbjWdzs.js +1 -0
  68. package/core/built/admin/assets/box-BWbhXh21.js +1 -0
  69. package/core/built/admin/assets/breadcrumb-B-M9Ip_2.js +1 -0
  70. package/core/built/admin/assets/card-DGoDJzrn.js +1 -0
  71. package/core/built/admin/assets/{chart-ChpW-NzQ.js → chart-BuRT2Y6p.js} +14 -14
  72. package/core/built/admin/assets/chart-helpers-xiSsW8r0.js +1 -0
  73. package/core/built/admin/assets/checkbox-EhJKHFdZ.js +1 -0
  74. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js → chunk.211.6f7328d63c41536451b3.js} +2025 -2819
  75. package/core/built/admin/assets/{chunk.432.c2caa0b20f03e71d1a35.js.LICENSE.txt → chunk.211.6f7328d63c41536451b3.js.LICENSE.txt} +1 -62
  76. package/core/built/admin/assets/{chunk.831.0703a12e49f51cec3f3a.js → chunk.361.3cdb584b973959e52ccc.js} +78 -85
  77. package/core/built/admin/assets/chunk.524.8365cd9280405c0f6216.js +25 -0
  78. package/core/built/admin/assets/chunk.582.61d078937e6102769f2c.js +27 -0
  79. package/core/built/admin/assets/code-editor-view-CZtJFGhR.js +1 -0
  80. package/core/built/admin/assets/comments-CvyXxOyN.js +1 -0
  81. package/core/built/admin/assets/container-BYz2Ed39.js +1 -0
  82. package/core/built/admin/assets/data-list-16rkJYYi.js +1 -0
  83. package/core/built/admin/assets/date-range-select-CTlyo8zW.js +1 -0
  84. package/core/built/admin/assets/disabled-sources-indicator-qs2GfLvl.js +1 -0
  85. package/core/built/admin/assets/{dist-DJ6c4_De.js → dist-2Tnz2Yfq.js} +1 -1
  86. package/core/built/admin/assets/{dist-CsekE4FL.js → dist-CQJY6SVY.js} +1 -1
  87. package/core/built/admin/assets/dist-CjY-f5Z1.js +1 -0
  88. package/core/built/admin/assets/dist-DGzPJ_bO.js +4 -0
  89. package/core/built/admin/assets/dist-DIC8yz5C.js +1 -0
  90. package/core/built/admin/assets/{dist-BbGrW05X.js → dist-DyViJwIy.js} +1 -1
  91. package/core/built/admin/assets/dist-Ndy-PuGN.js +1 -0
  92. package/core/built/admin/assets/dist-P_ohUlTi.js +1 -0
  93. package/core/built/admin/assets/domain-CPNXKVOV.js +1 -0
  94. package/core/built/admin/assets/dropzone-BmCXnw6J.js +5 -0
  95. package/core/built/admin/assets/edit-profile-SGrJve5M.js +1 -0
  96. package/core/built/admin/assets/editor-BOG2YPUm.js +8 -0
  97. package/core/built/admin/assets/empty-indicator-oX1u1Pkn.js +1 -0
  98. package/core/built/admin/assets/esm-CFX93H5M.js +2 -0
  99. package/core/built/admin/assets/explore-CUYLv9G9.js +1 -0
  100. package/core/built/admin/assets/feed-CPdJMttL.js +1 -0
  101. package/core/built/admin/assets/field-D0XISCK2.js +1 -0
  102. package/core/built/admin/assets/{filter-sources-v39ihhhV.js → filter-sources-Bieps75g.js} +1 -1
  103. package/core/built/admin/assets/filters-CuB-A7ma.js +1 -0
  104. package/core/built/admin/assets/filters-bXkkWro8.js +1 -0
  105. package/core/built/admin/assets/framework-provider-CmtnPXIT.js +4 -0
  106. package/core/built/admin/assets/{ghost-b57f077997b739a8ae9a70772dc016cb.js → ghost-05f9a7182ed56903dba05878a5b8422b.js} +46 -41
  107. package/core/built/admin/assets/ghost-dark-c8d0ab7f515b2010c173e23e9b32ea8a.css +1 -0
  108. package/core/built/admin/assets/gift-link-modal-su8MsRdg.js +1 -0
  109. package/core/built/admin/assets/{gift-links-CY3GwiVi.js → gift-links-nBxJjZiQ.js} +1 -1
  110. package/core/built/admin/assets/growth-Ba6S5FQX.js +1 -0
  111. package/core/built/admin/assets/hooks-BApwwBE0.js +2 -0
  112. package/core/built/admin/assets/{inbox-TEISAmth.js → inbox-Xx1CdnfO.js} +38 -38
  113. package/core/built/admin/assets/index-D8PbzuT9.css +1 -0
  114. package/core/built/admin/assets/index-ukW_0Uie.js +67 -0
  115. package/core/built/admin/assets/inline-EMAm3okk.js +1 -0
  116. package/core/built/admin/assets/input-group-CGOXcy4l.js +1 -0
  117. package/core/built/admin/assets/input-surface-BpAjZXY5.js +1 -0
  118. package/core/built/admin/assets/{react-dom-C6aoWSfl.js → jsx-runtime-DX3WBWVO.js} +1 -1
  119. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5 -2
  120. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +2 -2
  121. package/core/built/admin/assets/{koenig-lexical-Di7b48ED.js → koenig-lexical-B61IALf5.js} +2 -2
  122. package/core/built/admin/assets/kpi-card-BlZaG1Lo.js +1 -0
  123. package/core/built/admin/assets/kpi-card-DCdlyaSS.js +1 -0
  124. package/core/built/admin/assets/kpi-helpers-DpAuS1Nb.js +1 -0
  125. package/core/built/admin/assets/kpi-tabs-Dme44bQS.js +1 -0
  126. package/core/built/admin/assets/label-dSs5aepE.js +1 -0
  127. package/core/built/admin/assets/label-picker-Uq91atex.js +1 -0
  128. package/core/built/admin/assets/{labels-GbxlXWtf.js → labels-Cyayfd-e.js} +1 -1
  129. package/core/built/admin/assets/layout-WUcz6tu1.js +1 -0
  130. package/core/built/admin/assets/limit-service-9fwD33lU.js +20 -0
  131. package/core/built/admin/assets/link-helpers-tOlxmuH5.js +1 -0
  132. package/core/built/admin/assets/list-page-B6ANtzkd.js +1 -0
  133. package/core/built/admin/assets/mailchimp-Ds_NQ04w.svg +9 -0
  134. package/core/built/admin/assets/member-custom-fields-NCzrMuba.js +1 -0
  135. package/core/built/admin/assets/member-detail-DPWDtYnN.js +1 -0
  136. package/core/built/admin/assets/members-B9rO7qr4.js +10 -0
  137. package/core/built/admin/assets/modals-CxRaan1J.js +31 -0
  138. package/core/built/admin/assets/moderation-D8zon60E.js +1 -0
  139. package/core/built/admin/assets/multi-select-combobox-1wYm3nle.js +1 -0
  140. package/core/built/admin/assets/newsletter-DbYMRxRS.js +1 -0
  141. package/core/built/admin/assets/{newsletters-DZm3yLj8.js → newsletters-D1jbtV-h.js} +1 -1
  142. package/core/built/admin/assets/note-PiWPnnrh.js +1 -0
  143. package/core/built/admin/assets/notifications-DEgqqB9G.js +1 -0
  144. package/core/built/admin/assets/nql-lang-B7faUf8D.js +19 -0
  145. package/core/built/admin/assets/{offers-D11QtPXX.js → offers-CrY6nSRR.js} +1 -1
  146. package/core/built/admin/assets/onboarding-route-BzF6HeVn.js +1 -0
  147. package/core/built/admin/assets/overview-DixLeIqY.js +1 -0
  148. package/core/built/admin/assets/page-header-op0eN36I.js +1 -0
  149. package/core/built/admin/assets/{pages-BnObVRrf.js → pages-BbNWFcGj.js} +1 -1
  150. package/core/built/admin/assets/pintura-CXOmq-5H.svg +15 -0
  151. package/core/built/admin/assets/post-analytics-WwRDEnrV.js +1 -0
  152. package/core/built/admin/assets/post-analytics-header-DsMoLx0R.js +1 -0
  153. package/core/built/admin/assets/{post-analytics-provider-DSfBCtnj.js → post-analytics-provider-BJCPLMIb.js} +1 -1
  154. package/core/built/admin/assets/post-share-modal-Dx-MEjhI.js +1 -0
  155. package/core/built/admin/assets/{posts-CwH8VJvB.js → posts-EWpZIjkr.js} +1 -1
  156. package/core/built/admin/assets/preferences-D7-j6A4C.js +5 -0
  157. package/core/built/admin/assets/profile-Dl69QPp0.js +1 -0
  158. package/core/built/admin/assets/{referrers-nxR52jPI.js → referrers-BCfFYSHc.js} +1 -1
  159. package/core/built/admin/assets/router-provider-C1R4AZ2o.js +1 -0
  160. package/core/built/admin/assets/select-C1qDZnW4.js +1 -0
  161. package/core/built/admin/assets/settings-BbmC_Iqq.js +4 -0
  162. package/core/built/admin/assets/settings-H6HxFgfI.js +1 -0
  163. package/core/built/admin/assets/shade-app-B3heOAfz-CGXQwWeO.js +3 -0
  164. package/core/built/admin/assets/share-modal-BJCadJyp.js +1 -0
  165. package/core/built/admin/assets/social-urls-BPL1nADp.js +8 -0
  166. package/core/built/admin/assets/sort-button-DyYlfYp7.js +1 -0
  167. package/core/built/admin/assets/source-icon-_ubRDbg_.js +1 -0
  168. package/core/built/admin/assets/stack-xiN0eQ6Z.js +1 -0
  169. package/core/built/admin/assets/stats-BQZMGMvn.js +1 -0
  170. package/core/built/admin/assets/stats-view-Doei-qCX.js +1 -0
  171. package/core/built/admin/assets/step-1-IKiLBPoC.js +1 -0
  172. package/core/built/admin/assets/step-2-jJ41PsDN.js +1 -0
  173. package/core/built/admin/assets/step-3-CaqFAEqf.js +2 -0
  174. package/core/built/admin/assets/switch-t-WyENU2.js +1 -0
  175. package/core/built/admin/assets/table-DxUL78jU.js +1 -0
  176. package/core/built/admin/assets/tabs-BQcJQ1ke.js +1 -0
  177. package/core/built/admin/assets/tags-CNujGwkT.js +1 -0
  178. package/core/built/admin/assets/text-DwtjwGkh.js +1 -0
  179. package/core/built/admin/assets/textarea-Bjccvh_E.js +1 -0
  180. package/core/built/admin/assets/{tiers-EghDzCKc.js → tiers-BgYLWRJv.js} +1 -1
  181. package/core/built/admin/assets/toggle-group-BeEpQ69p.js +1 -0
  182. package/core/built/admin/assets/topic-filter-Bb5MOD-1.js +1 -0
  183. package/core/built/admin/assets/{use-analytics-data-0l_OHtnR.js → use-analytics-data-Cds6XDjg.js} +1 -1
  184. package/core/built/admin/assets/use-filter-params-DjXkhO54.js +1 -0
  185. package/core/built/admin/assets/use-growth-stats-D8uf98-G.js +1 -0
  186. package/core/built/admin/assets/{use-post-referrers-DwI31Ril.js → use-post-referrers-CRtgyuXB.js} +1 -1
  187. package/core/built/admin/assets/use-reply-chain-data-DbKYX50v.js +1 -0
  188. package/core/built/admin/assets/use-simple-pagination-DC01kpo0.js +1 -0
  189. package/core/built/admin/assets/{use-tinybird-query-DvZBBMG7.js → use-tinybird-query-C7bQRJWw.js} +1 -1
  190. package/core/built/admin/assets/{use-tinybird-token-CQtebkvU.js → use-tinybird-token-Az4tam7_.js} +1 -1
  191. package/core/built/admin/assets/{users-Pc8IRjk9.js → users-CcSCQFcQ.js} +1 -1
  192. package/core/built/admin/assets/virtual-list-Dhuh9fGx.js +1 -0
  193. package/core/built/admin/assets/web-LtHNiNBV.js +1 -0
  194. package/core/built/admin/index.html +22 -22
  195. package/core/frontend/apps/private-blogging/index.js +1 -1
  196. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  197. package/core/frontend/helpers/split.js +2 -1
  198. package/core/frontend/meta/asset-url.js +1 -1
  199. package/core/frontend/meta/author-image.js +1 -1
  200. package/core/frontend/meta/blog-logo.js +1 -1
  201. package/core/frontend/meta/canonical-url.js +1 -1
  202. package/core/frontend/meta/cover-image.js +1 -1
  203. package/core/frontend/meta/get-meta.js +1 -1
  204. package/core/frontend/meta/og-image.js +1 -1
  205. package/core/frontend/meta/paginated-url.js +1 -1
  206. package/core/frontend/meta/twitter-image.js +1 -1
  207. package/core/frontend/meta/url.js +1 -1
  208. package/core/frontend/services/assets-minification/admin-auth-assets.js +1 -1
  209. package/core/frontend/services/llms/handler.js +1 -1
  210. package/core/frontend/services/proxy.js +42 -3
  211. package/core/frontend/services/routing/collection-router.js +1 -1
  212. package/core/frontend/services/routing/controllers/email-post.js +1 -1
  213. package/core/frontend/services/routing/controllers/entry/markdown.js +1 -1
  214. package/core/frontend/services/routing/controllers/entry/markdown.ts +1 -1
  215. package/core/frontend/services/routing/controllers/entry.js +1 -1
  216. package/core/frontend/services/routing/controllers/entry.ts +1 -1
  217. package/core/frontend/services/routing/controllers/previews.js +6 -7
  218. package/core/frontend/services/routing/controllers/unsubscribe.js +7 -3
  219. package/core/frontend/services/routing/email-router.js +1 -1
  220. package/core/frontend/services/routing/events.js +12 -0
  221. package/core/frontend/services/routing/middleware/page-param.js +1 -1
  222. package/core/frontend/services/routing/parent-router.js +1 -1
  223. package/core/frontend/services/routing/preview-router.js +1 -1
  224. package/core/frontend/services/routing/router-manager.js +4 -8
  225. package/core/frontend/services/routing/rss-router.js +1 -1
  226. package/core/frontend/services/routing/static-pages-router.js +1 -1
  227. package/core/frontend/services/routing/static-routes-router.js +1 -1
  228. package/core/frontend/services/routing/taxonomy-router.js +1 -1
  229. package/core/frontend/services/rss/generate-feed.js +1 -1
  230. package/core/frontend/services/sitemap/base-site-map-generator.js +23 -4
  231. package/core/frontend/services/sitemap/site-map-index-generator.js +1 -1
  232. package/core/frontend/services/sitemap/site-map-manager.js +14 -8
  233. package/core/frontend/services/sitemap/utils.js +1 -1
  234. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +1 -1
  235. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +1 -1
  236. package/core/frontend/utils/images.js +1 -1
  237. package/core/frontend/web/middleware/admin-toolbar.js +1 -1
  238. package/core/frontend/web/middleware/handle-image-sizes.js +2 -2
  239. package/core/frontend/web/middleware/redirect-ghost-to-admin.js +1 -1
  240. package/core/frontend/web/routers/serve-favicon.js +1 -1
  241. package/core/frontend/web/routers/serve-public-file.js +1 -1
  242. package/core/frontend/web/site.js +5 -5
  243. package/core/server/adapters/cache/AdapterCacheMemoryTTL.js +2 -2
  244. package/core/server/adapters/cache/MemoryCache.js +2 -2
  245. package/core/server/adapters/cache/Redis.js +1 -1
  246. package/core/server/adapters/cache/index.js +1 -1
  247. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +2 -2
  248. package/core/server/adapters/route-settings/FileStore.js +2 -8
  249. package/core/server/adapters/route-settings/FileStore.ts +1 -6
  250. package/core/server/adapters/route-settings/S3RouteSettingsStore.js +206 -0
  251. package/core/server/adapters/route-settings/S3RouteSettingsStore.ts +199 -0
  252. package/core/server/adapters/route-settings/utils.js +13 -0
  253. package/core/server/adapters/route-settings/utils.ts +7 -0
  254. package/core/server/adapters/scheduling/deps.d.ts +0 -2
  255. package/core/server/adapters/scheduling/error-capture.js +76 -0
  256. package/core/server/adapters/scheduling/error-capture.ts +91 -0
  257. package/core/server/adapters/scheduling/utils.js +18 -34
  258. package/core/server/adapters/scheduling/utils.ts +36 -0
  259. package/core/server/adapters/storage/LocalFilesStorage.js +13 -11
  260. package/core/server/adapters/storage/LocalFilesStorage.ts +24 -0
  261. package/core/server/adapters/storage/LocalImagesStorage.js +14 -12
  262. package/core/server/adapters/storage/LocalImagesStorage.ts +24 -0
  263. package/core/server/adapters/storage/LocalMediaStorage.js +13 -11
  264. package/core/server/adapters/storage/LocalMediaStorage.ts +24 -0
  265. package/core/server/adapters/storage/LocalStorageBase.js +107 -167
  266. package/core/server/adapters/storage/LocalStorageBase.ts +342 -0
  267. package/core/server/adapters/storage/S3Storage.js +2 -2
  268. package/core/server/adapters/storage/S3Storage.ts +1 -1
  269. package/core/server/adapters/storage/utils.js +36 -50
  270. package/core/server/adapters/storage/utils.ts +60 -0
  271. package/core/server/api/endpoints/authentication.js +1 -1
  272. package/core/server/api/endpoints/db.js +6 -0
  273. package/core/server/api/endpoints/featurebase.js +1 -1
  274. package/core/server/api/endpoints/files.js +2 -2
  275. package/core/server/api/endpoints/images.js +2 -2
  276. package/core/server/api/endpoints/libraries.d.ts +0 -1
  277. package/core/server/api/endpoints/media.js +8 -5
  278. package/core/server/api/endpoints/member-custom-fields.js +4 -1
  279. package/core/server/api/endpoints/member-custom-fields.ts +4 -1
  280. package/core/server/api/endpoints/members.js +25 -28
  281. package/core/server/api/endpoints/pages.js +6 -1
  282. package/core/server/api/endpoints/posts.js +28 -3
  283. package/core/server/api/endpoints/search-index-public.js +4 -3
  284. package/core/server/api/endpoints/search-index.js +5 -4
  285. package/core/server/api/endpoints/settings-public.js +1 -1
  286. package/core/server/api/endpoints/settings.js +3 -1
  287. package/core/server/api/endpoints/utils/serializers/input/utils/url.js +9 -1
  288. package/core/server/api/endpoints/utils/serializers/output/default.js +7 -0
  289. package/core/server/api/endpoints/utils/serializers/output/files.js +1 -1
  290. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +4 -1
  291. package/core/server/api/endpoints/utils/serializers/output/media.js +1 -1
  292. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.js +7 -4
  293. package/core/server/api/endpoints/utils/serializers/output/member-custom-fields.ts +8 -4
  294. package/core/server/api/endpoints/utils/serializers/output/members.js +27 -106
  295. package/core/server/api/endpoints/utils/serializers/output/pages.js +7 -0
  296. package/core/server/api/endpoints/utils/serializers/output/posts.js +13 -0
  297. package/core/server/api/endpoints/utils/serializers/output/utils/url.js +1 -1
  298. package/core/server/api/endpoints/utils/validators/input/members.js +2 -52
  299. package/core/server/data/db/backup.js +1 -1
  300. package/core/server/data/exporter/export-filename.js +2 -1
  301. package/core/server/data/importer/handlers/image.js +3 -3
  302. package/core/server/data/importer/import-manager.js +6 -4
  303. package/core/server/data/importer/importers/content-file-importer.js +2 -2
  304. package/core/server/data/importer/importers/data/revue-subscriber-importer.js +6 -10
  305. package/core/server/data/importer/importers/json-to-html.js +24 -4
  306. package/core/server/data/migrations/utils/schema.js +4 -2
  307. package/core/server/data/migrations/versions/6.54/2026-07-19-16-59-00-add-content-import-permission.js +10 -0
  308. package/core/server/data/migrations/versions/6.54/2026-07-20-13-59-21-drop-email-tracked-sent-count-from-automation-action-revisions.js +7 -0
  309. package/core/server/data/migrations/versions/6.54/2026-07-21-01-58-20-add-automation-run-steps-poller-index.js +3 -0
  310. package/core/server/data/migrations/versions/6.54/2026-07-21-21-08-15-add-automated-email-recipients-mailgun-message-id-index.js +3 -0
  311. package/core/server/data/migrations/versions/6.54/2026-07-22-10-41-08-add-click-tracking-to-automated-email-recipients.js +13 -0
  312. package/core/server/data/migrations/versions/6.54/2026-07-22-15-10-30-add-email-clicked-count-to-automation-action-revisions.js +7 -0
  313. package/core/server/data/migrations/versions/6.54/2026-07-23-10-24-18-add-automation-action-revision-to-redirects.js +9 -0
  314. package/core/server/data/schema/commands.js +37 -3
  315. package/core/server/data/schema/fixtures/fixtures.json +7 -0
  316. package/core/server/data/schema/lib/default-index-name.js +20 -0
  317. package/core/server/data/schema/schema.js +40 -17
  318. package/core/server/data/seeders/data-generator.js +4 -2
  319. package/core/server/lib/image/image-size.js +7 -23
  320. package/core/server/lib/image/image-utils.js +16 -2
  321. package/core/server/lib/image/index.js +4 -4
  322. package/core/server/lib/lexical.js +3 -3
  323. package/core/server/lib/mobiledoc.js +2 -2
  324. package/core/server/lib/request-external.js +1 -1
  325. package/core/server/lib/validate-password.js +1 -1
  326. package/core/server/models/action.js +9 -0
  327. package/core/server/models/base/plugins/generate-slug.js +1 -1
  328. package/core/server/models/collection.js +1 -1
  329. package/core/server/models/custom-theme-setting.js +1 -1
  330. package/core/server/models/member.js +73 -0
  331. package/core/server/models/newsletter.js +1 -1
  332. package/core/server/models/post.js +19 -5
  333. package/core/server/models/posts-meta.js +1 -1
  334. package/core/server/models/redirect.js +1 -1
  335. package/core/server/models/settings.js +1 -1
  336. package/core/server/models/snippet.js +1 -1
  337. package/core/server/models/tag.js +1 -1
  338. package/core/server/models/user.js +47 -71
  339. package/core/server/models/welcome-email-automated-email.js +1 -1
  340. package/core/server/services/activitypub/activity-pub-service-wrapper.js +1 -1
  341. package/core/server/services/adapter-manager/adapter-manager.js +5 -1
  342. package/core/server/services/adapter-manager/adapter-manager.ts +7 -2
  343. package/core/server/services/adapter-manager/index.js +18 -15
  344. package/core/server/services/adapter-manager/index.ts +23 -17
  345. package/core/server/services/adapter-manager/utils.js +124 -14
  346. package/core/server/services/adapter-manager/utils.ts +130 -14
  347. package/core/server/services/api-version-compatibility/mw-version-rewrites.js +1 -1
  348. package/core/server/services/audience-feedback/index.js +1 -1
  349. package/core/server/services/auth/passwordreset.js +1 -1
  350. package/core/server/services/auth/session/express-session.js +1 -1
  351. package/core/server/services/auth/session/index.js +2 -2
  352. package/core/server/services/auth/session/session-service.js +29 -2
  353. package/core/server/services/automations/automations-api.js +8 -25
  354. package/core/server/services/automations/automations-api.ts +8 -37
  355. package/core/server/services/automations/automations-repository.ts +16 -0
  356. package/core/server/services/automations/database-automations-repository.js +37 -4
  357. package/core/server/services/automations/database-automations-repository.ts +41 -4
  358. package/core/server/services/automations/poll.js +16 -12
  359. package/core/server/services/automations/poll.ts +17 -15
  360. package/core/server/services/automations/service.js +1 -1
  361. package/core/server/services/automations/service.ts +3 -13
  362. package/core/server/services/automations/welcome-email-automation-poll.js +2 -1
  363. package/core/server/services/comments/comments-service-emails.js +4 -1
  364. package/core/server/services/comments/index.js +1 -1
  365. package/core/server/services/custom-redirects/index.js +2 -2
  366. package/core/server/services/email-analytics/email-analytics-service-wrapper.js +14 -13
  367. package/core/server/services/email-analytics/email-analytics-service.js +1 -1
  368. package/core/server/services/email-analytics/events/start-email-analytics-job-event.js +11 -15
  369. package/core/server/services/email-analytics/events/start-email-analytics-job-event.ts +15 -0
  370. package/core/server/services/email-analytics/index.js +2 -3
  371. package/core/server/services/email-analytics/index.ts +1 -2
  372. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.js +1 -6
  373. package/core/server/services/email-analytics/jobs/email-analytics-job-scheduler.ts +0 -9
  374. package/core/server/services/email-analytics/jobs/fetch-latest/index.js +1 -1
  375. package/core/server/services/email-analytics/jobs/index.js +0 -2
  376. package/core/server/services/email-service/email-service-wrapper.js +1 -1
  377. package/core/server/services/email-service/email-service.js +20 -4
  378. package/core/server/services/explore-ping/explore-ping-service.js +24 -39
  379. package/core/server/services/explore-ping/explore-ping-service.ts +198 -0
  380. package/core/server/services/explore-ping/index.js +11 -11
  381. package/core/server/services/explore-ping/index.ts +42 -0
  382. package/core/server/services/gifts/gift-reminder-scheduler.js +1 -1
  383. package/core/server/services/gifts/gift-reminder-scheduler.ts +1 -1
  384. package/core/server/services/gifts/gift-service-wrapper.js +1 -1
  385. package/core/server/services/identity-tokens/identity-token-service-wrapper.js +1 -1
  386. package/core/server/services/indexnow-ping/constants.js +30 -0
  387. package/core/server/services/indexnow-ping/constants.ts +32 -0
  388. package/core/server/services/indexnow-ping/index.js +29 -253
  389. package/core/server/services/indexnow-ping/index.ts +37 -0
  390. package/core/server/services/indexnow-ping/indexnow-ping-service.js +229 -0
  391. package/core/server/services/indexnow-ping/indexnow-ping-service.ts +319 -0
  392. package/core/server/services/invites/index.js +1 -1
  393. package/core/server/services/lib/mailgun-client.js +3 -3
  394. package/core/server/services/link-redirection/index.js +2 -2
  395. package/core/server/services/link-redirection/link-redirect-repository.js +1 -1
  396. package/core/server/services/link-redirection/link-redirect.js +12 -13
  397. package/core/server/services/link-redirection/link-redirect.ts +22 -0
  398. package/core/server/services/link-redirection/link-redirects-service.js +1 -1
  399. package/core/server/services/link-tracking/full-post-link.js +2 -2
  400. package/core/server/services/link-tracking/index.js +1 -1
  401. package/core/server/services/mail/ghost-mailer.js +1 -1
  402. package/core/server/services/mail/index.js +1 -1
  403. package/core/server/services/media-inliner/external-media-inliner.js +2 -2
  404. package/core/server/services/media-inliner/service.js +4 -3
  405. package/core/server/services/member-attribution/index.js +1 -1
  406. package/core/server/services/member-welcome-emails/service.js +1 -1
  407. package/core/server/services/members/api.js +8 -2
  408. package/core/server/services/members/import-export/config.js +30 -0
  409. package/core/server/services/members/import-export/config.ts +34 -0
  410. package/core/server/services/members/import-export/csv/index.js +10 -0
  411. package/core/server/services/members/import-export/csv/index.ts +2 -0
  412. package/core/server/services/members/import-export/csv/parse.js +64 -0
  413. package/core/server/services/members/import-export/csv/parse.ts +69 -0
  414. package/core/server/services/members/import-export/csv/serialize.js +13 -0
  415. package/core/server/services/members/import-export/csv/serialize.ts +18 -0
  416. package/core/server/services/members/import-export/export/exporter.js +202 -0
  417. package/core/server/services/members/import-export/export/exporter.ts +325 -0
  418. package/core/server/services/members/import-export/import/completion-email.js +65 -0
  419. package/core/server/services/members/import-export/import/completion-email.ts +119 -0
  420. package/core/server/services/members/import-export/import/importer.js +276 -0
  421. package/core/server/services/members/import-export/import/importer.ts +430 -0
  422. package/core/server/services/members/import-export/import/reader.js +32 -0
  423. package/core/server/services/members/import-export/import/reader.ts +33 -0
  424. package/core/server/services/members/import-export/import/row.js +33 -0
  425. package/core/server/services/members/import-export/import/row.ts +52 -0
  426. package/core/server/services/members/import-export/import/spool.js +30 -0
  427. package/core/server/services/members/import-export/import/spool.ts +38 -0
  428. package/core/server/services/members/import-export/index.js +90 -0
  429. package/core/server/services/members/import-export/index.ts +118 -0
  430. package/core/server/services/members/members-api/controllers/router-controller.js +7 -0
  431. package/core/server/services/members/members-api/members-api.js +4 -2
  432. package/core/server/services/members/members-api/repositories/event-repository.js +13 -2
  433. package/core/server/services/members/members-api/services/member-bread-service.js +42 -19
  434. package/core/server/services/members/middleware.js +1 -1
  435. package/core/server/services/members/service.js +28 -17
  436. package/core/server/services/members/stripe-connect.js +1 -1
  437. package/core/server/services/members-custom-fields/actions.js +3 -0
  438. package/core/server/services/members-custom-fields/actions.ts +6 -2
  439. package/core/server/services/members-custom-fields/config.js +34 -0
  440. package/core/server/services/members-custom-fields/config.ts +38 -0
  441. package/core/server/services/members-custom-fields/definitions-service.js +156 -21
  442. package/core/server/services/members-custom-fields/definitions-service.ts +170 -25
  443. package/core/server/services/members-custom-fields/index.js +16 -3
  444. package/core/server/services/members-custom-fields/index.ts +17 -3
  445. package/core/server/services/members-custom-fields/values-service.js +56 -10
  446. package/core/server/services/members-custom-fields/values-service.ts +62 -10
  447. package/core/server/services/mentions/mention-sending-service.js +22 -2
  448. package/core/server/services/mentions/service.js +21 -5
  449. package/core/server/services/newsletters/index.js +1 -1
  450. package/core/server/services/oembed/oembed-service.js +122 -33
  451. package/core/server/services/oembed/service.js +4 -2
  452. package/core/server/services/offers/service.js +1 -1
  453. package/core/server/services/post-scheduling/index.js +4 -3
  454. package/core/server/services/post-scheduling/index.ts +4 -3
  455. package/core/server/services/post-scheduling/post-scheduling.js +1 -1
  456. package/core/server/services/post-scheduling/post-scheduling.ts +1 -1
  457. package/core/server/services/posts/post-email-handler.js +13 -6
  458. package/core/server/services/posts/post-scheduling.js +1 -1
  459. package/core/server/services/posts/posts-exporter.js +6 -4
  460. package/core/server/services/posts/posts-service-instance.js +1 -1
  461. package/core/server/services/posts/posts-service.js +4 -4
  462. package/core/server/services/posts-public/service.js +1 -1
  463. package/core/server/services/public-config/site.js +1 -1
  464. package/core/server/services/recommendations/recommendation-service-wrapper.js +1 -1
  465. package/core/server/services/recommendations/service/libraries.d.ts +0 -2
  466. package/core/server/services/route-settings/dynamic-routing-service.js +2 -3
  467. package/core/server/services/route-settings/index.js +1 -1
  468. package/core/server/services/route-settings/route-settings-parser.js +134 -124
  469. package/core/server/services/route-settings/route-settings-parser.ts +160 -125
  470. package/core/server/services/route-settings/validation-errors.js +178 -0
  471. package/core/server/services/route-settings/validation-errors.ts +196 -0
  472. package/core/server/services/settings/settings-service.js +2 -2
  473. package/core/server/services/settings-helpers/index.js +1 -1
  474. package/core/server/services/slack-notifications/service.js +1 -1
  475. package/core/server/services/slack-ping/constants.js +16 -0
  476. package/core/server/services/slack-ping/constants.ts +15 -0
  477. package/core/server/services/slack-ping/index.js +26 -204
  478. package/core/server/services/slack-ping/index.ts +35 -0
  479. package/core/server/services/slack-ping/slack-ping-service.js +214 -0
  480. package/core/server/services/slack-ping/slack-ping-service.ts +296 -0
  481. package/core/server/services/staff/index.js +1 -1
  482. package/core/server/services/stats/posts-stats-service.js +1 -1
  483. package/core/server/services/stats/service.js +1 -1
  484. package/core/server/services/stripe/service.js +1 -1
  485. package/core/server/services/tags-public/service.js +1 -1
  486. package/core/server/services/themes/storage.js +9 -0
  487. package/core/server/services/themes/theme-storage.js +1 -1
  488. package/core/server/services/themes/validate.js +1 -1
  489. package/core/server/services/update-check/index.js +1 -1
  490. package/core/server/services/url/lazy-url-service.js +66 -6
  491. package/core/server/services/url/lazy-url-service.ts +73 -6
  492. package/core/server/services/url/url-generator.js +1 -1
  493. package/core/server/services/url/url-service-facade.js +68 -3
  494. package/core/server/services/url/url-service-facade.ts +79 -4
  495. package/core/server/services/url/url-service.js +1 -1
  496. package/core/server/services/url/urls.js +1 -1
  497. package/core/server/services/webhooks/index.js +19 -2
  498. package/core/server/services/webhooks/listen.js +6 -11
  499. package/core/server/services/webhooks/payload.js +1 -3
  500. package/core/server/services/webhooks/serialize.js +16 -1
  501. package/core/server/web/admin/app.js +1 -1
  502. package/core/server/web/admin/middleware/redirect-admin-urls.js +1 -1
  503. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  504. package/core/server/web/api/middleware/cors.js +1 -1
  505. package/core/server/web/api/middleware/upload.js +4 -0
  506. package/core/server/web/gift-preview/controller.js +1 -1
  507. package/core/server/web/shared/middleware/redirect-amp-urls.js +1 -1
  508. package/core/server/web/shared/middleware/uncapitalise.js +2 -2
  509. package/core/server/web/shared/middleware/url-redirects.js +1 -1
  510. package/core/shared/config/defaults.json +10 -2
  511. package/core/shared/config/overrides.json +4 -0
  512. package/core/shared/express.js +6 -1
  513. package/core/shared/labs.js +2 -1
  514. package/core/shared/url-utils.js +19 -15
  515. package/core/shared/url-utils.ts +20 -0
  516. package/ghost.js +0 -1
  517. package/package.json +30 -35
  518. package/pnpm-lock.yaml +681 -2789
  519. package/pnpm-workspace.yaml +31 -17
  520. package/components/tryghost-adapter-base-scheduling-0.0.0.tgz +0 -0
  521. package/components/tryghost-adapter-base-sso-0.0.0.tgz +0 -0
  522. package/core/built/admin/assets/Combination--5EZGaDs.js +0 -43
  523. package/core/built/admin/assets/Growth-C0NoKcHQ.js +0 -3
  524. package/core/built/admin/assets/Newsletters-Ed8kDjdy.js +0 -1
  525. package/core/built/admin/assets/Overview-CArPgRZt.js +0 -1
  526. package/core/built/admin/assets/Web-CjjYoVM3.js +0 -2
  527. package/core/built/admin/assets/account-migration-mfa5mNI9.js +0 -1
  528. package/core/built/admin/assets/activitypub/inbox-B3rjKMTv.js +0 -1221
  529. package/core/built/admin/assets/activitypub/layout-jcurg3rU.js +0 -1
  530. package/core/built/admin/assets/activitypub/use-activity-pub-queries-yqGRcnLn.js +0 -2569
  531. package/core/built/admin/assets/activitypub/users-CfyHIsTG.js +0 -1316
  532. package/core/built/admin/assets/automations-DkUnxNdv.js +0 -1
  533. package/core/built/admin/assets/automations-vjXofmV_.js +0 -1
  534. package/core/built/admin/assets/bluesky-sharing-T-pO3RcP.js +0 -1
  535. package/core/built/admin/assets/breadcrumb-CekPYTCn.js +0 -1
  536. package/core/built/admin/assets/button--i2uMDDn.js +0 -4
  537. package/core/built/admin/assets/card-CSWz_BXq.js +0 -1
  538. package/core/built/admin/assets/chart-helpers-C_4Ka_vT.js +0 -1
  539. package/core/built/admin/assets/chunk.524.8ce2c741473e2f0929dc.js +0 -25
  540. package/core/built/admin/assets/chunk.582.453459d6228d2955408b.js +0 -27
  541. package/core/built/admin/assets/code-editor-view-BfkwQto2.js +0 -1
  542. package/core/built/admin/assets/command-K75Jzs0G.js +0 -1
  543. package/core/built/admin/assets/comments-BEIi1DH-.js +0 -1
  544. package/core/built/admin/assets/container-BNXvlcjA.js +0 -1
  545. package/core/built/admin/assets/data-list-BmK5QMab.js +0 -1
  546. package/core/built/admin/assets/date-range-select-5sKzwbt7.js +0 -1
  547. package/core/built/admin/assets/disabled-sources-indicator-L_ssJTNr.js +0 -1
  548. package/core/built/admin/assets/dist-BBIJuyPg.js +0 -1
  549. package/core/built/admin/assets/dist-BHE0dp6o.js +0 -1
  550. package/core/built/admin/assets/dist-CT46_f_J.js +0 -1
  551. package/core/built/admin/assets/dist-DW0QXQO3.js +0 -1
  552. package/core/built/admin/assets/dist-DxFLceO5.js +0 -1
  553. package/core/built/admin/assets/dist-QcACAOAD.js +0 -1
  554. package/core/built/admin/assets/dist-duxRDcQu.js +0 -177
  555. package/core/built/admin/assets/domain-CLaPZ9Rc.js +0 -1
  556. package/core/built/admin/assets/dropzone-E0bSX4_a.js +0 -5
  557. package/core/built/admin/assets/edit-profile-DqNPKaA4.js +0 -1
  558. package/core/built/admin/assets/editor-CkLXQDRp.js +0 -8
  559. package/core/built/admin/assets/empty-indicator-BTtOlgIo.js +0 -1
  560. package/core/built/admin/assets/esm-TSfGW7nz.js +0 -2
  561. package/core/built/admin/assets/explore-BEstLxKr.js +0 -1
  562. package/core/built/admin/assets/feed-C58p2voG.js +0 -1
  563. package/core/built/admin/assets/field-BSbDUHPv.js +0 -1
  564. package/core/built/admin/assets/filters-BgYv8Gt7.js +0 -1
  565. package/core/built/admin/assets/filters-DvenFkmK.js +0 -1
  566. package/core/built/admin/assets/framework-provider-jQktxm9P.js +0 -4
  567. package/core/built/admin/assets/ghost-dark-8590dea6cd695ff90f27d262c4464538.css +0 -1
  568. package/core/built/admin/assets/gift-link-modal-BPjXkEFt.js +0 -1
  569. package/core/built/admin/assets/growth-D4JNiVTe.js +0 -1
  570. package/core/built/admin/assets/hooks-Cjxexi_I.js +0 -2
  571. package/core/built/admin/assets/index-BacwlcOy.js +0 -67
  572. package/core/built/admin/assets/index-DxRNHH0o.css +0 -1
  573. package/core/built/admin/assets/inline-C22rnPro.js +0 -1
  574. package/core/built/admin/assets/input-group-CKfrILLP.js +0 -1
  575. package/core/built/admin/assets/jsx-runtime-CtMZ-PAS.js +0 -1
  576. package/core/built/admin/assets/kpi-card-DZxQKAIb.js +0 -1
  577. package/core/built/admin/assets/kpi-card-FidQ5zg3.js +0 -1
  578. package/core/built/admin/assets/kpi-helpers-C5T8Vaf1.js +0 -1
  579. package/core/built/admin/assets/kpi-tabs-_VRK6hGV.js +0 -1
  580. package/core/built/admin/assets/label-Cza7hPgn.js +0 -1
  581. package/core/built/admin/assets/label-picker-DgC_zLaw.js +0 -1
  582. package/core/built/admin/assets/layout-BxsXnKFX.js +0 -1
  583. package/core/built/admin/assets/limit-service-CTurluJQ.js +0 -20
  584. package/core/built/admin/assets/link-helpers-C3Gqy2cz.js +0 -1
  585. package/core/built/admin/assets/list-page-BtqCnow_.js +0 -1
  586. package/core/built/admin/assets/member-custom-fields-9uXFBqSt.js +0 -1
  587. package/core/built/admin/assets/member-detail-Dq6ZDIxo.js +0 -1
  588. package/core/built/admin/assets/members-CUWD9jal.js +0 -10
  589. package/core/built/admin/assets/modals-CIdwHVga.js +0 -31
  590. package/core/built/admin/assets/moderation-DTt04UDA.js +0 -1
  591. package/core/built/admin/assets/newsletter-cC8vcc9h.js +0 -1
  592. package/core/built/admin/assets/note-DZU0IY9e.js +0 -1
  593. package/core/built/admin/assets/notifications-NoHpBHJ4.js +0 -1
  594. package/core/built/admin/assets/nql-lang-CvCSOQG3.js +0 -19
  595. package/core/built/admin/assets/onboarding-route-Deg2hNm8.js +0 -1
  596. package/core/built/admin/assets/overview-BQPt_9w3.js +0 -1
  597. package/core/built/admin/assets/page-header-D6bEqPo2.js +0 -1
  598. package/core/built/admin/assets/post-analytics-header-BPw_B2_D.js +0 -1
  599. package/core/built/admin/assets/post-analytics-kp2_--XO.js +0 -1
  600. package/core/built/admin/assets/post-share-modal-Cave3Z4W.js +0 -1
  601. package/core/built/admin/assets/preferences-C7h3j_uy.js +0 -5
  602. package/core/built/admin/assets/profile-B2x4q2oB.js +0 -1
  603. package/core/built/admin/assets/router-provider-5fsX1CYn.js +0 -1
  604. package/core/built/admin/assets/select-PhPjIBBT.js +0 -1
  605. package/core/built/admin/assets/settings-D5P9Gwgo.js +0 -6
  606. package/core/built/admin/assets/settings-zUOzQV5I.js +0 -1
  607. package/core/built/admin/assets/share-modal-EfpfbuWF.js +0 -1
  608. package/core/built/admin/assets/social-urls-DgAF08Xc.js +0 -18
  609. package/core/built/admin/assets/sort-button-WOQYJm2H.js +0 -1
  610. package/core/built/admin/assets/source-icon-hm8Cj-Gx.js +0 -1
  611. package/core/built/admin/assets/stats-CnQDb62m.js +0 -1
  612. package/core/built/admin/assets/stats-view-CCfTJgSe.js +0 -1
  613. package/core/built/admin/assets/step-1-BGlhY4DS.js +0 -1
  614. package/core/built/admin/assets/step-2-D3sDEyFH.js +0 -1
  615. package/core/built/admin/assets/step-3-CvZoUdsc.js +0 -2
  616. package/core/built/admin/assets/switch-CNjkOmwz.js +0 -1
  617. package/core/built/admin/assets/table-C5nZYPnW.js +0 -1
  618. package/core/built/admin/assets/tabs-dtOcExye.js +0 -1
  619. package/core/built/admin/assets/tags-Dhm0FB_g.js +0 -1
  620. package/core/built/admin/assets/textarea-CeKw3wmV.js +0 -1
  621. package/core/built/admin/assets/toggle-group-DfhZIMTW.js +0 -1
  622. package/core/built/admin/assets/topic-filter-Cxe1Il41.js +0 -1
  623. package/core/built/admin/assets/typeof-Ca-duI-z.js +0 -1
  624. package/core/built/admin/assets/use-filter-params-Bub6BqNy.js +0 -1
  625. package/core/built/admin/assets/use-growth-stats-BJORomv0.js +0 -1
  626. package/core/built/admin/assets/use-reply-chain-data-B89YjVoo.js +0 -1
  627. package/core/built/admin/assets/use-simple-pagination-BL2SYXKi.js +0 -1
  628. package/core/built/admin/assets/virtual-list-DNJOSK9I.js +0 -1
  629. package/core/built/admin/assets/web-BHUE3YQc.js +0 -1
  630. package/core/server/adapters/scheduling/scheduling-base.js +0 -5
  631. package/core/server/adapters/sso/SSOBase.js +0 -5
  632. package/core/server/adapters/storage/index.js +0 -17
  633. package/core/server/services/mail/templates/newsletter.html +0 -876
  634. package/core/server/services/members/exporter/query.js +0 -206
  635. package/core/server/services/members/importer/index.js +0 -30
  636. package/core/server/services/members/importer/labels.js +0 -125
  637. package/core/server/services/members/importer/members-csv-importer.js +0 -502
  638. /package/core/server/services/members/{importer → import-export/import}/email-template.js +0 -0
  639. /package/core/server/services/members/{importer/members-csv-importer-stripe-utils.js → import-export/import/stripe-utils.js} +0 -0
@@ -14,10 +14,13 @@ const queries_1 = require("./queries");
14
14
  const storage_1 = require("./storage");
15
15
  const FIELDS_TABLE = 'members_custom_fields';
16
16
  const VALUES_TABLE = 'members_custom_field_values';
17
- // Values arrive keyed by field key. The values themselves stay `unknown` here —
18
- // each one is validated by its own field type's schema, which isn't known until
19
- // the key is resolved to a definition.
20
- const ValuesInput = zod_1.z.record(zod_1.z.string(), zod_1.z.unknown());
17
+ // Matches the `members_custom_fields.key` column (schema.js), so no key a site
18
+ // could actually have minted is ever refused by it.
19
+ const MAX_KEY_LENGTH = 191;
20
+ // Values arrive keyed by field key. Each value stays `unknown` here: it is
21
+ // validated by its own field type's schema, which isn't known until the key is
22
+ // resolved to a definition.
23
+ const ValuesInput = zod_1.z.record(zod_1.z.string().max(MAX_KEY_LENGTH), zod_1.z.unknown());
21
24
  /**
22
25
  * The value half of member custom fields: reading and writing what a member holds
23
26
  * for each defined field. It belongs to the member aggregate — a value is data
@@ -31,8 +34,15 @@ const ValuesInput = zod_1.z.record(zod_1.z.string(), zod_1.z.unknown());
31
34
  */
32
35
  class CustomFieldValuesService {
33
36
  knex;
34
- constructor({ knex }) {
37
+ /**
38
+ * @private
39
+ * A getter rather than a number: the ceiling is an operator setting that can
40
+ * change between requests.
41
+ */
42
+ getMaxDefinitions;
43
+ constructor({ knex, getMaxDefinitions }) {
35
44
  this.knex = knex;
45
+ this.getMaxDefinitions = getMaxDefinitions;
36
46
  }
37
47
  /**
38
48
  * The active fields for a set of keys, keyed by key, for resolving a write.
@@ -97,6 +107,33 @@ class CustomFieldValuesService {
97
107
  }
98
108
  return byMember;
99
109
  }
110
+ /**
111
+ * @private
112
+ * Input as the values object it claims to be, rejecting anything that isn't
113
+ * one. Shared by every caller so they cannot disagree on what a values object
114
+ * is, or on the error when it isn't one.
115
+ */
116
+ parseValues(input) {
117
+ const parsed = ValuesInput.safeParse(input);
118
+ if (!parsed.success) {
119
+ throw new errors_1.default.ValidationError({ message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields' });
120
+ }
121
+ return parsed.data;
122
+ }
123
+ /**
124
+ * Whether input names any values. An absent key names none; anything present
125
+ * that isn't a values object throws, with the same error resolving it would
126
+ * have raised.
127
+ *
128
+ * Answers the shape question alone, with no catalog lookup, so it can be asked
129
+ * before a write is known to be permitted.
130
+ */
131
+ namesValues(input) {
132
+ if (input === undefined) {
133
+ return false;
134
+ }
135
+ return Object.keys(this.parseValues(input)).length > 0;
136
+ }
100
137
  /**
101
138
  * Resolve input into the writes it implies, rejecting anything invalid, and
102
139
  * writing nothing. Returned so a caller can validate before it commits to a
@@ -104,13 +141,22 @@ class CustomFieldValuesService {
104
141
  * apply the same plan without re-resolving or re-validating.
105
142
  */
106
143
  async planWrite(input) {
107
- const parsed = ValuesInput.safeParse(input);
108
- if (!parsed.success) {
109
- throw new errors_1.default.ValidationError({ message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields' });
144
+ const values = this.parseValues(input);
145
+ const keys = Object.keys(values);
146
+ // A write cannot name more fields than the site may define, so the
147
+ // definitions ceiling bounds it. This also holds the lookup below within the
148
+ // database driver's bound-parameter limit, which one key per parameter would
149
+ // otherwise exceed.
150
+ const maxKeys = this.getMaxDefinitions();
151
+ if (keys.length > maxKeys) {
152
+ throw new errors_1.default.ValidationError({
153
+ message: `Custom field values are limited to ${maxKeys} fields per request.`,
154
+ property: 'custom_fields'
155
+ });
110
156
  }
111
- const byKey = await this.activeFieldsByKey(Object.keys(parsed.data));
157
+ const byKey = await this.activeFieldsByKey(keys);
112
158
  const writes = [];
113
- for (const [key, raw] of Object.entries(parsed.data)) {
159
+ for (const [key, raw] of Object.entries(values)) {
114
160
  const field = byKey.get(key);
115
161
  if (!field) {
116
162
  // Unknown (or archived) key. Rejected rather than ignored: a typo
@@ -11,10 +11,14 @@ import {storageCodecFor, storageColumnsFor} from './storage';
11
11
  const FIELDS_TABLE = 'members_custom_fields';
12
12
  const VALUES_TABLE = 'members_custom_field_values';
13
13
 
14
- // Values arrive keyed by field key. The values themselves stay `unknown` here —
15
- // each one is validated by its own field type's schema, which isn't known until
16
- // the key is resolved to a definition.
17
- const ValuesInput = z.record(z.string(), z.unknown());
14
+ // Matches the `members_custom_fields.key` column (schema.js), so no key a site
15
+ // could actually have minted is ever refused by it.
16
+ const MAX_KEY_LENGTH = 191;
17
+
18
+ // Values arrive keyed by field key. Each value stays `unknown` here: it is
19
+ // validated by its own field type's schema, which isn't known until the key is
20
+ // resolved to a definition.
21
+ const ValuesInput = z.record(z.string().max(MAX_KEY_LENGTH), z.unknown());
18
22
 
19
23
  // The field facts the value path needs: the id to write the FK, the key to match
20
24
  // input against, the name for error messages, and the type to pick the validator
@@ -47,9 +51,16 @@ interface PlannedWrite {
47
51
  */
48
52
  export class CustomFieldValuesService {
49
53
  private knex: Knex;
54
+ /**
55
+ * @private
56
+ * A getter rather than a number: the ceiling is an operator setting that can
57
+ * change between requests.
58
+ */
59
+ private getMaxDefinitions: () => number;
50
60
 
51
- constructor({knex}: {knex: Knex}) {
61
+ constructor({knex, getMaxDefinitions}: {knex: Knex, getMaxDefinitions: () => number}) {
52
62
  this.knex = knex;
63
+ this.getMaxDefinitions = getMaxDefinitions;
53
64
  }
54
65
 
55
66
  /**
@@ -119,6 +130,37 @@ export class CustomFieldValuesService {
119
130
  return byMember;
120
131
  }
121
132
 
133
+ /**
134
+ * @private
135
+ * Input as the values object it claims to be, rejecting anything that isn't
136
+ * one. Shared by every caller so they cannot disagree on what a values object
137
+ * is, or on the error when it isn't one.
138
+ */
139
+ private parseValues(input: unknown): Record<string, unknown> {
140
+ const parsed = ValuesInput.safeParse(input);
141
+ if (!parsed.success) {
142
+ throw new errors.ValidationError({message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields'});
143
+ }
144
+
145
+ return parsed.data;
146
+ }
147
+
148
+ /**
149
+ * Whether input names any values. An absent key names none; anything present
150
+ * that isn't a values object throws, with the same error resolving it would
151
+ * have raised.
152
+ *
153
+ * Answers the shape question alone, with no catalog lookup, so it can be asked
154
+ * before a write is known to be permitted.
155
+ */
156
+ namesValues(input: unknown): boolean {
157
+ if (input === undefined) {
158
+ return false;
159
+ }
160
+
161
+ return Object.keys(this.parseValues(input)).length > 0;
162
+ }
163
+
122
164
  /**
123
165
  * Resolve input into the writes it implies, rejecting anything invalid, and
124
166
  * writing nothing. Returned so a caller can validate before it commits to a
@@ -126,15 +168,25 @@ export class CustomFieldValuesService {
126
168
  * apply the same plan without re-resolving or re-validating.
127
169
  */
128
170
  async planWrite(input: unknown): Promise<PlannedWrite[]> {
129
- const parsed = ValuesInput.safeParse(input);
130
- if (!parsed.success) {
131
- throw new errors.ValidationError({message: 'Custom field values must be an object keyed by field key.', property: 'custom_fields'});
171
+ const values = this.parseValues(input);
172
+ const keys = Object.keys(values);
173
+
174
+ // A write cannot name more fields than the site may define, so the
175
+ // definitions ceiling bounds it. This also holds the lookup below within the
176
+ // database driver's bound-parameter limit, which one key per parameter would
177
+ // otherwise exceed.
178
+ const maxKeys = this.getMaxDefinitions();
179
+ if (keys.length > maxKeys) {
180
+ throw new errors.ValidationError({
181
+ message: `Custom field values are limited to ${maxKeys} fields per request.`,
182
+ property: 'custom_fields'
183
+ });
132
184
  }
133
185
 
134
- const byKey = await this.activeFieldsByKey(Object.keys(parsed.data));
186
+ const byKey = await this.activeFieldsByKey(keys);
135
187
  const writes: PlannedWrite[] = [];
136
188
 
137
- for (const [key, raw] of Object.entries(parsed.data)) {
189
+ for (const [key, raw] of Object.entries(values)) {
138
190
  const field = byKey.get(key);
139
191
  if (!field) {
140
192
  // Unknown (or archived) key. Rejected rather than ignored: a typo
@@ -5,14 +5,16 @@ module.exports = class MentionSendingService {
5
5
  #discoveryService;
6
6
  #externalRequest;
7
7
  #getSiteUrl;
8
+ #getPostData;
8
9
  #getPostUrl;
9
10
  #isEnabled;
10
11
  #jobService;
11
12
 
12
- constructor({discoveryService, externalRequest, getSiteUrl, getPostUrl, isEnabled, jobService}) {
13
+ constructor({discoveryService, externalRequest, getSiteUrl, getPostData, getPostUrl, isEnabled, jobService}) {
13
14
  this.#discoveryService = discoveryService;
14
15
  this.#externalRequest = externalRequest;
15
16
  this.#getSiteUrl = getSiteUrl;
17
+ this.#getPostData = getPostData;
16
18
  this.#getPostUrl = getPostUrl;
17
19
  this.#isEnabled = isEnabled;
18
20
  this.#jobService = jobService;
@@ -66,9 +68,12 @@ module.exports = class MentionSendingService {
66
68
  let html = post.get('status') === 'published' ? post.get('html') : null;
67
69
  let previousHtml = post.previous('status') === 'published' ? post.previous('html') : null;
68
70
  if (html || previousHtml) {
71
+ // Capture the source URL now, from the event's data, rather than
72
+ // deferring the model into the job.
73
+ const url = new URL(await this.#resolvePostUrl(post));
69
74
  await this.#jobService.addJob('sendWebmentions', async () => {
70
75
  await this.sendForHTMLResource({
71
- url: new URL(this.#getPostUrl(post)),
76
+ url,
72
77
  html: html,
73
78
  previousHtml: previousHtml
74
79
  });
@@ -80,6 +85,21 @@ module.exports = class MentionSendingService {
80
85
  }
81
86
  }
82
87
 
88
+ // Deleting a published post fires `unpublished` from onDestroyed with the
89
+ // model already destroyed: its own attributes are cleared, but its previous
90
+ // state and loaded relations remain. Resolve the URL from that previous
91
+ // data, the same way we read previous('html') above; live models resolve
92
+ // straight from the model.
93
+ async #resolvePostUrl(post) {
94
+ // A deleted post arrives destroyed: its own attributes are cleared, so
95
+ // its data lives in the previous attributes (its relations remain).
96
+ // A live post loads whatever the URL service still needs.
97
+ if (post.attributes && Object.keys(post.attributes).length === 0) {
98
+ return this.#getPostUrl(post.previous('id'), {...post.toJSON(), ...post.previousAttributes()});
99
+ }
100
+ return this.#getPostUrl(post.id, await this.#getPostData(post));
101
+ }
102
+
83
103
  /**
84
104
  * @param {{source: URL, target: URL, endpoint: URL}} options
85
105
  * @returns
@@ -9,16 +9,27 @@ const RoutingService = require('./routing-service');
9
9
  const models = require('../../models');
10
10
  const events = require('../../lib/common/events');
11
11
  const externalRequest = require('../../../server/lib/request-external.js');
12
- const urlUtils = require('../../../shared/url-utils');
12
+ const urlUtils = require('../../../shared/url-utils').default;
13
13
  const outputSerializerUrlUtil = require('../../../server/api/endpoints/utils/serializers/output/utils/url');
14
14
  const urlService = require('../url');
15
15
  const settingsCache = require('../../../shared/settings-cache');
16
16
  const DomainEvents = require('@tryghost/domain-events');
17
17
  const jobsService = require('../mentions-jobs');
18
18
 
19
- function getPostUrl(post) {
20
- const jsonModel = post.toJSON();
21
- outputSerializerUrlUtil.forPost(post.id, jsonModel, {options: {}});
19
+ // Serializes a post model to the data the URL service needs, loading the
20
+ // relations it reads for filtered collections (event-emitted models don't
21
+ // reliably carry them).
22
+ async function getPostData(post) {
23
+ const missing = urlService.facade.getRequiredRelations().filter(relation => !post.relations[relation]);
24
+ if (missing.length) {
25
+ await post.load(missing);
26
+ }
27
+ return post.toJSON();
28
+ }
29
+
30
+ function getPostUrl(id, postData) {
31
+ const jsonModel = {...postData};
32
+ outputSerializerUrlUtil.forPost(id, jsonModel, {options: {}});
22
33
  return jsonModel.url;
23
34
  }
24
35
 
@@ -99,7 +110,8 @@ module.exports = {
99
110
  discoveryService,
100
111
  externalRequest,
101
112
  getSiteUrl: () => urlUtils.urlFor('home', true),
102
- getPostUrl: post => getPostUrl(post),
113
+ getPostData: post => getPostData(post),
114
+ getPostUrl: (id, data) => getPostUrl(id, data),
103
115
  isEnabled: () => !settingsCache.get('is_private'),
104
116
  jobService: {
105
117
  async addJob(name, fn) {
@@ -116,3 +128,7 @@ module.exports = {
116
128
  this.sendingService = sendingService;
117
129
  }
118
130
  };
131
+
132
+ // exposed for testing
133
+ module.exports.getPostData = getPostData;
134
+ module.exports.getPostUrl = getPostUrl;
@@ -2,7 +2,7 @@ const NewslettersService = require('./newsletters-service.js');
2
2
  const SingleUseTokenProvider = require('../members/single-use-token-provider');
3
3
  const mail = require('../mail');
4
4
  const models = require('../../models');
5
- const urlUtils = require('../../../shared/url-utils');
5
+ const urlUtils = require('../../../shared/url-utils').default;
6
6
  const limitService = require('../limits');
7
7
  const labs = require('../../../shared/labs');
8
8
  const emailAddressService = require('../email-address');
@@ -13,6 +13,8 @@ const crypto = require('crypto');
13
13
  // Some sites block non-standard user agents so we need to mimic a typical browser
14
14
  // Note: the Ghost/5.0 string _may_ be in use by 3rd parties so use caution when updating across majors
15
15
  const USER_AGENT = 'Mozilla/5.0 (compatible; Ghost/5.0; +https://ghost.org/)';
16
+ const DEFAULT_BOOKMARK_ICON = 'https://static.ghost.org/v5.0.0/images/link-icon.svg';
17
+ const DEFAULT_REQUEST_TIMEOUT = 5000;
16
18
 
17
19
  // metascraper-amazon's built-in URL test is a substring regex that misfires on
18
20
  // any host ending in a letter followed by `.co/` (e.g. `rangemedia.co`), causing
@@ -77,9 +79,8 @@ const findUrlWithProvider = (url) => {
77
79
  */
78
80
 
79
81
  /**
80
- * @typedef {Object} IStorage
81
- * @prop {(feature: string) => Object} getStorage
82
- */
82
+ * @typedef {import('ghost-storage-base').StorageBase} IImageStore
83
+ *
83
84
 
84
85
  /**
85
86
  * @typedef {import('got').GotRequestFunction} IExternalRequest
@@ -96,12 +97,12 @@ class OEmbedService {
96
97
  *
97
98
  * @param {Object} dependencies
98
99
  * @param {IConfig} dependencies.config
99
- * @param {IStorage} dependencies.storage
100
+ * @param {IImageStore} dependencies.imageStore
100
101
  * @param {IExternalRequest} dependencies.externalRequest
101
102
  */
102
- constructor({config, externalRequest, storage}) {
103
+ constructor({config, externalRequest, imageStore}) {
103
104
  this.config = config;
104
- this.storage = storage;
105
+ this.imageStore = imageStore;
105
106
 
106
107
  /** @type {IExternalRequest} */
107
108
  this.externalRequest = externalRequest;
@@ -130,12 +131,13 @@ class OEmbedService {
130
131
 
131
132
  /**
132
133
  * @param {string} url
134
+ * @param {Object} [options]
133
135
  */
134
- async knownProvider(url) {
136
+ async knownProvider(url, options = {}) {
135
137
  const {extract} = require('@extractus/oembed-extractor');
136
138
 
137
139
  try {
138
- return await extract(url);
140
+ return await extract(url, {}, options);
139
141
  } catch (err) {
140
142
  if (err.message === 'Request failed with error code 401' || err.message === 'Request failed with error code 403') {
141
143
  throw new errors.ValidationError({
@@ -163,25 +165,66 @@ class OEmbedService {
163
165
 
164
166
  /**
165
167
  * Process and store image from a URL
166
- * @param {string} imageUrl - URL of the image to process
168
+ * @param {string|null|undefined} imageUrl - URL of the image to process
167
169
  * @param {string} imageType - What is the image used for. Example - icon, thumbnail
168
- * @returns {Promise<String>} - URL where the image is stored
170
+ * @returns {Promise<String|null>} - URL where the image is stored
169
171
  */
170
172
  async processImageFromUrl(imageUrl, imageType) {
173
+ if (!imageUrl) {
174
+ return null;
175
+ }
176
+
171
177
  // Fetch image buffer from the URL
172
178
  const imageBuffer = await this.fetchImageBuffer(imageUrl);
173
- const store = this.storage.getStorage('images');
174
179
 
175
180
  // Extract file name from URL
176
181
  const fileName = path.basename(new URL(imageUrl).pathname);
177
182
  const ext = path.extname(fileName);
178
183
  const baseName = ext ? path.basename(fileName, ext) : fileName;
179
- const name = store.getSanitizedFileName(baseName);
184
+ const name = this.imageStore.getSanitizedFileName(baseName);
180
185
 
181
186
  const uniqueFileName = `${name}-${crypto.randomUUID()}${ext}`;
182
187
  const targetPath = path.join(imageType, uniqueFileName);
183
188
 
184
- return store.saveRaw(imageBuffer, targetPath);
189
+ return this.imageStore.saveRaw(imageBuffer, targetPath);
190
+ }
191
+
192
+ /**
193
+ * Fetch bookmark enrichment from an allowlisted oEmbed provider without
194
+ * exposing provider-supplied HTML.
195
+ *
196
+ * @param {string} url
197
+ * @param {Object} [options]
198
+ * @returns {Promise<Object|undefined>}
199
+ */
200
+ async fetchBookmarkEnrichment(url, options = {}) {
201
+ const {url: providerUrl, provider} = findUrlWithProvider(url);
202
+ if (!provider) {
203
+ return;
204
+ }
205
+
206
+ const timeout = options.timeout?.request ?? DEFAULT_REQUEST_TIMEOUT;
207
+ const signal = AbortSignal.timeout(timeout);
208
+
209
+ let oembed;
210
+ try {
211
+ oembed = await this.knownProvider(providerUrl, {signal});
212
+ } catch {
213
+ // oEmbed metadata is a best-effort enhancement. If it fails, keep
214
+ // the bookmark metadata scraped from the page.
215
+ return;
216
+ }
217
+
218
+ if (!oembed) {
219
+ return;
220
+ }
221
+
222
+ return _.pickBy({
223
+ title: oembed.title,
224
+ author: oembed.author_name,
225
+ publisher: oembed.provider_name,
226
+ thumbnail: oembed.thumbnail_url || (oembed.type === 'photo' ? oembed.url : undefined)
227
+ }, value => value !== null && value !== undefined && value !== '');
185
228
  }
186
229
 
187
230
  /**
@@ -198,7 +241,7 @@ class OEmbedService {
198
241
  'user-agent': USER_AGENT
199
242
  },
200
243
  timeout: {
201
- request: 5000
244
+ request: DEFAULT_REQUEST_TIMEOUT
202
245
  },
203
246
  followRedirect: true,
204
247
  ...options
@@ -274,6 +317,8 @@ class OEmbedService {
274
317
  /**
275
318
  * @param {string} url
276
319
  * @param {string} html
320
+ * @param {string} type
321
+ * @param {Object} [enrichment]
277
322
  *
278
323
  * @returns {Promise<{
279
324
  * version: '1.0',
@@ -285,7 +330,7 @@ class OEmbedService {
285
330
  * }
286
331
  * }>}
287
332
  */
288
- async fetchBookmarkData(url, html, type) {
333
+ async fetchBookmarkData(url, html, type, enrichment = {}) {
289
334
  const requestOptions = this.externalRequest.defaults?.options || {};
290
335
  const gotOpts = {
291
336
  hooks: requestOptions.hooks,
@@ -374,11 +419,24 @@ class OEmbedService {
374
419
  const metadata = Object.assign({}, scraperResponse, {
375
420
  thumbnail: scraperResponse.image,
376
421
  icon: scraperResponse.logo
377
- });
422
+ }, enrichment);
378
423
  // We want to use standard naming for image and logo
379
424
  delete metadata.image;
380
425
  delete metadata.logo;
381
426
 
427
+ return this.buildBookmarkData(url, metadata, type);
428
+ }
429
+
430
+ /**
431
+ * Validate and process bookmark metadata after it has been scraped,
432
+ * enriched, or assembled from enrichment alone.
433
+ *
434
+ * @param {string} url
435
+ * @param {Object} metadata
436
+ * @param {string} type
437
+ * @returns {Promise<Object>}
438
+ */
439
+ async buildBookmarkData(url, metadata, type) {
382
440
  if (!metadata.title) {
383
441
  throw new errors.ValidationError({
384
442
  message: tpl(messages.insufficientMetadata),
@@ -391,24 +449,31 @@ class OEmbedService {
391
449
  try {
392
450
  await this.externalRequest.head(metadata.icon);
393
451
  } catch (err) {
394
- metadata.icon = 'https://static.ghost.org/v5.0.0/images/link-icon.svg';
452
+ metadata.icon = DEFAULT_BOOKMARK_ICON;
395
453
  logging.error(err);
396
454
  }
397
455
  }
398
456
  } else {
399
- await this.processImageFromUrl(metadata.icon, 'icon')
400
- .then((processedImageUrl) => {
401
- metadata.icon = processedImageUrl;
402
- }).catch((err) => {
403
- metadata.icon = 'https://static.ghost.org/v5.0.0/images/link-icon.svg';
404
- logging.error(err);
405
- });
406
- await this.processImageFromUrl(metadata.thumbnail, 'thumbnail')
407
- .then((processedImageUrl) => {
408
- metadata.thumbnail = processedImageUrl;
409
- }).catch((err) => {
410
- logging.error(err);
411
- });
457
+ if (metadata.icon) {
458
+ await this.processImageFromUrl(metadata.icon, 'icon')
459
+ .then((processedImageUrl) => {
460
+ metadata.icon = processedImageUrl;
461
+ }).catch((err) => {
462
+ metadata.icon = DEFAULT_BOOKMARK_ICON;
463
+ logging.error(err);
464
+ });
465
+ } else {
466
+ metadata.icon = DEFAULT_BOOKMARK_ICON;
467
+ }
468
+
469
+ if (metadata.thumbnail) {
470
+ await this.processImageFromUrl(metadata.thumbnail, 'thumbnail')
471
+ .then((processedImageUrl) => {
472
+ metadata.thumbnail = processedImageUrl;
473
+ }).catch((err) => {
474
+ logging.error(err);
475
+ });
476
+ }
412
477
  }
413
478
 
414
479
  return {
@@ -508,7 +573,7 @@ class OEmbedService {
508
573
  * @param {string} url - oembed URL
509
574
  * @param {string} type - card type
510
575
  * @param {Object} [options] Specific fetch options
511
- * @param {number} [options.timeout] Change the default timeout for fetching html
576
+ * @param {Object} [options.timeout] Change the default request timeout, got-style ({request: ms})
512
577
  *
513
578
  * @returns {Promise<Object>}
514
579
  */
@@ -553,11 +618,35 @@ class OEmbedService {
553
618
  }
554
619
 
555
620
  // Not in the list, we need to fetch the content
556
- const {url: pageUrl, body, contentType} = await this.fetchPageHtml(url, fetchOptions);
621
+ const bookmarkEnrichmentPromise = type === 'bookmark' ? this.fetchBookmarkEnrichment(url, fetchOptions) : undefined;
622
+ const [pageResult, enrichmentResult] = await Promise.allSettled([
623
+ this.fetchPageHtml(url, fetchOptions),
624
+ bookmarkEnrichmentPromise
625
+ ]);
626
+ const bookmarkEnrichment = enrichmentResult.status === 'fulfilled' ? enrichmentResult.value : undefined;
627
+
628
+ if (pageResult.status === 'rejected') {
629
+ if (type === 'bookmark' && bookmarkEnrichment?.title) {
630
+ return this.buildBookmarkData(url, {
631
+ url,
632
+ title: null,
633
+ description: null,
634
+ author: null,
635
+ publisher: null,
636
+ thumbnail: null,
637
+ icon: null,
638
+ ...bookmarkEnrichment
639
+ }, type);
640
+ }
641
+
642
+ throw pageResult.reason;
643
+ }
644
+
645
+ const {url: pageUrl, body, contentType} = pageResult.value;
557
646
 
558
647
  // fetch only bookmark when explicitly requested
559
648
  if (type === 'bookmark') {
560
- return this.fetchBookmarkData(url, body, type);
649
+ return this.fetchBookmarkData(url, body, type, bookmarkEnrichment);
561
650
  }
562
651
 
563
652
  // mentions need to return bookmark data (metadata) and body (html) for link verification
@@ -1,9 +1,11 @@
1
1
  const config = require('../../../shared/config');
2
- const storage = require('../../adapters/storage');
2
+ const adapterManager = require('../../services/adapter-manager').default;
3
3
  const externalRequest = require('../../lib/request-external');
4
4
 
5
5
  const OEmbedService = require('./oembed-service');
6
- const oembed = new OEmbedService({config, externalRequest, storage});
6
+
7
+ const imageStore = adapterManager.getAdapter('storage:images');
8
+ const oembed = new OEmbedService({config, externalRequest, imageStore});
7
9
 
8
10
  const NFT = require('./nft-oembed-provider');
9
11
  const nft = new NFT({
@@ -1,6 +1,6 @@
1
1
  const DynamicRedirectManager = require('../lib/dynamic-redirect-manager');
2
2
  const config = require('../../../shared/config');
3
- const urlUtils = require('../../../shared/url-utils');
3
+ const urlUtils = require('../../../shared/url-utils').default;
4
4
  const models = require('../../models');
5
5
  const OfferBookshelfRepository = require('./offer-bookshelf-repository');
6
6
  const OffersModule = require('./offers-module');
@@ -5,11 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const post_scheduling_1 = __importDefault(require("./post-scheduling"));
7
7
  const internal_keys_1 = __importDefault(require("../internal-keys"));
8
+ const adapter_manager_1 = __importDefault(require("../adapter-manager"));
9
+ const error_capture_1 = require("../../adapters/scheduling/error-capture");
8
10
  // CJS modules without TS declarations — typed loosely at the boundary.
9
- const adapterManager = require('../adapter-manager');
10
- const urlUtils = require('../../../shared/url-utils');
11
+ const urlUtils = require('../../../shared/url-utils').default;
11
12
  exports.default = new post_scheduling_1.default({
12
13
  apiUrl: urlUtils.urlFor('api', { type: 'admin' }, true),
13
- adapter: adapterManager.getAdapter('scheduling'),
14
+ adapter: (0, error_capture_1.withErrorCapture)(adapter_manager_1.default.getAdapter('scheduling')),
14
15
  internalKeys: internal_keys_1.default
15
16
  });
@@ -1,12 +1,13 @@
1
1
  import PostScheduling from './post-scheduling';
2
2
  import internalKeys from '../internal-keys';
3
+ import adapterManager from '../adapter-manager';
4
+ import {withErrorCapture} from '../../adapters/scheduling/error-capture';
3
5
 
4
6
  // CJS modules without TS declarations — typed loosely at the boundary.
5
- const adapterManager = require('../adapter-manager');
6
- const urlUtils = require('../../../shared/url-utils');
7
+ const urlUtils = require('../../../shared/url-utils').default;
7
8
 
8
9
  export default new PostScheduling({
9
10
  apiUrl: urlUtils.urlFor('api', {type: 'admin'}, true),
10
- adapter: adapterManager.getAdapter('scheduling'),
11
+ adapter: withErrorCapture(adapterManager.getAdapter('scheduling')),
11
12
  internalKeys
12
13
  });
@@ -8,7 +8,7 @@ const logging_1 = __importDefault(require("@tryghost/logging"));
8
8
  // CJS-only modules — typed loosely below. models is the Bookshelf registry
9
9
  // without TS declarations; the rest are JS modules without types.
10
10
  const models = require('../../models');
11
- const urlUtils = require('../../../shared/url-utils');
11
+ const urlUtils = require('../../../shared/url-utils').default;
12
12
  const { getSignedAdminToken } = require('../../adapters/scheduling/utils');
13
13
  const events = require('../../lib/common/events');
14
14
  // Pages live in the posts table with type:'page', so both types are